/***************************************************************************************

***************************************************************************************/



/*
*************************************************************************************
* File name: macroblock.c
* Function: Process one macroblock
*
*************************************************************************************
*/


#include "contributors.h"

#include <math.h>
#include <stdlib.h>
#include <assert.h>

#include "macroblock.h"
#include "refbuf.h"
#include "vlc.h"
#include "block.h"
#include "header.h"
#include "golomb.h"
#include "intra-prediction.h"


/*<!*******EDIT START BY lzhang ******************/
#include "AEC.h" 
/*<!*******EDIT end BY lzhang ******************/

extern const byte QP_SCALE_CR[64];
extern const int NCBP[64][2];

int chroma_trans8x8(int tmp_block[2][8][8],int tmp_mpr[2][8][8],int *cbpc);


extern int DELTA_QP,DELTA_QP2;
extern int QP,QP2;

extern  int check_mv_range(int mv_x, int mv_y, int pix_x, int pix_y, int blocktype);	


extern void SetMotionVectorPredictor (int  pmv[2],int  **refFrArr,int  ***tmp_mv,int  ref_frame,int  mb_pix_x,
	int  mb_pix_y,int  blockshape_x,int  blockshape_y,int  ref,int  direct_mv);

const int ref_idx[32] = {0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, 4, -1, -1, -1, 5, -1, -1, -1, 6, -1, -1, -1, 7, -1, -1, -1, 8, -1, -1, -1, 9};

extern int* mvbits;

/*
*************************************************************************
* Function:Update the coordinates for the next macroblock to be processed
* Input:mb: MB address in scan order
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void set_MB_parameters (int mb)
{
	const int number_mb_per_row = img->width / MB_BLOCK_SIZE ; 

	img->current_mb_nr = mb;
	img->mb_x = mb % number_mb_per_row;
	img->mb_y = mb / number_mb_per_row;

	// Define vertical positions
	img->block8_y= img->mb_y * BLOCK_SIZE/2;
	img->block_y = img->mb_y * BLOCK_SIZE;        // vertical luma block position
	img->pix_y   = img->mb_y * MB_BLOCK_SIZE;     // vertical luma macroblock position
	img->pix_c_y = img->mb_y * MB_BLOCK_SIZE/2;   // vertical chroma macroblock position

	// Define horizontal positions
	img->block8_x= img->mb_x * BLOCK_SIZE/2;
	img->block_x = img->mb_x * BLOCK_SIZE;        // luma block
	img->pix_x   = img->mb_x * MB_BLOCK_SIZE;     // luma pixel
	img->block_c_x = img->mb_x * BLOCK_SIZE/2;    // chroma block
	img->pix_c_x   = img->mb_x * MB_BLOCK_SIZE/2; // chroma pixel  
}

/*
*************************************************************************
* Function:Update the coordinates and statistics parameter for the
next macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void proceed2nextMacroblock()
{
	Macroblock *currMB = &img->mb_data[img->current_mb_nr];
	int*        bitCount = currMB->bitcounter;

#if TRACE
	int i;
	if (p_trace)
	{
		fprintf(p_trace, "\n*********** Pic: %i (I/P) MB: %i Slice: %i **********\n\n", frame_no, img->current_mb_nr, img->current_slice_nr);
		// Write out the tracestring for each symbol
		for (i=0; i<currMB->currSEnr; i++)
			trace2out(&(img->MB_SyntaxElements[i]));
	}
#endif

	// Update the statistics
	stat->bit_use_mb_type[img->type]      += bitCount[BITS_MB_MODE];
	stat->bit_use_coeffY[img->type]       += bitCount[BITS_COEFF_Y_MB] ;
	stat->tmp_bit_use_cbp[img->type]      += bitCount[BITS_CBP_MB];
	stat->bit_use_coeffC[img->type]       += bitCount[BITS_COEFF_UV_MB];
	stat->bit_use_delta_quant[img->type]  += bitCount[BITS_DELTA_QUANT_MB];

	if (img->type==I_IMG)
		++stat->mode_use_intra[currMB->mb_type];
	else
		if (img->type != B_IMG)
		{
			++stat->mode_use_inter[0][currMB->mb_type];
			stat->bit_use_mode_inter[0][currMB->mb_type]+= bitCount[BITS_INTER_MB];

		}
		else
		{
			stat->bit_use_mode_inter[1][currMB->mb_type]+= bitCount[BITS_INTER_MB];
			++stat->mode_use_inter[1][currMB->mb_type];
		}

		// Statistics
		if ((img->type == P_IMG) )
		{
			++stat->quant0;
			stat->quant1 += img->qp;      // to find average quant for inter frames
		}

}

/*
*************************************************************************
* Function:initializes the current macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void start_macroblock()
{
	int i,j,k,l;
	Macroblock *currMB = &img->mb_data[img->current_mb_nr];

	// Save the slice number of this macroblock. When the macroblock below
	// is coded it will use this to decide if prediction for above is possible
	img->current_slice_nr = img->mb_data[img->current_mb_nr].slice_nr;    
	currMB->slice_nr = img->current_slice_nr;



	currMB->delta_qp = 0;
	currMB->qp       = img->qp;       // needed in loop filter (even if constant QP is used)


	// Initialize counter for MB symbols
	currMB->currSEnr=0;

	// If MB is next to a slice boundary, mark neighboring blocks unavailable for prediction
	CheckAvailabilityOfNeighbors(img);
	CheckAvailabilityOfNeighborsAEC();

	currMB->mb_type   = 0;

	// Reset vectors before doing motion search in motion_search().
	if (img->type != B_IMG)  
	{
		for (k=0; k < 2; k++)
		{
			for (j=0; j < BLOCK_MULTIPLE; j++)
				for (i=0; i < BLOCK_MULTIPLE; i++)
					tmp_mv[k][img->block_y+j][img->block_x+i+4]=0;
		}
	}

	// Reset syntax element entries in MB struct
	currMB->mb_type   = 0;
	currMB->cbp       = 0;

	for (l=0; l < 2; l++)
		for (j=0; j < BLOCK_MULTIPLE; j++)
			for (i=0; i < BLOCK_MULTIPLE; i++)
				for (k=0; k < 2; k++)
					currMB->mvd[l][j][i][k] = 0;

	currMB->cbp_bits   = 0;
	currMB->c_ipred_mode = DC_PRED_8; 

	for (i=0; i < 16; i++)
		currMB->intra_pred_modes[i] = DC_PRED;

	// store filtering parameters for this MB;
	currMB->lf_disable = input->loop_filter_disable;

	// Initialize bitcounters for this macroblock
	if(img->current_mb_nr == 0) // No slice header to account for
	{
		currMB->bitcounter[BITS_HEADER] = 0;
	}
	else if (currMB->slice_nr == img->mb_data[img->current_mb_nr-1].slice_nr) // current MB belongs to the
		// same slice as the last MB
	{
		currMB->bitcounter[BITS_HEADER] = 0;
	}

	currMB->bitcounter[BITS_MB_MODE] = 0;
	currMB->bitcounter[BITS_COEFF_Y_MB] = 0;
	currMB->bitcounter[BITS_INTER_MB] = 0;
	currMB->bitcounter[BITS_CBP_MB] = 0;
	currMB->bitcounter[BITS_DELTA_QUANT_MB] = 0;
	currMB->bitcounter[BITS_COEFF_UV_MB] = 0;

}

/*
*************************************************************************
* Function:Terminate processing of the current macroblock depending
on the chosen slice mode
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void terminate_macroblock(Boolean *end_of_picture)
{
	Macroblock    *currMB    = &img->mb_data[img->current_mb_nr];
	SyntaxElement *currSE    = &img->MB_SyntaxElements[currMB->currSEnr];


	int rlc_bits=0;
	static int skip = FALSE;
	int mb_width = img->width/16;
	int slice_mb = input->slice_row_nr*mb_width;


	img->coded_mb_nr++;


	if(input->slice_row_nr && (img->coded_mb_nr != img->total_number_mb))
	{
		if(img->coded_mb_nr%slice_mb == 0 )
		{
			img->mb_data[img->current_mb_nr+1].slice_nr = img->mb_data[img->current_mb_nr].slice_nr+1;  
			img->mb_no_currSliceLastMB =  min(img->mb_no_currSliceLastMB + slice_mb, img->total_number_mb-1) ;  
		}
		else
			img->mb_data[img->current_mb_nr+1].slice_nr = img->mb_data[img->current_mb_nr].slice_nr;
	}



	if (img->coded_mb_nr == img->total_number_mb) // maximum number of MBs reached
	{
		*end_of_picture = TRUE;
		img->coded_mb_nr= 0;
	}


	if(*end_of_picture == TRUE && img->cod_counter)
	{
		currSE->value1 = img->cod_counter;
		currSE->mapping = ue_linfo;
		currSE->type = SE_MBTYPE;
		//! Edit Start  by ZL 
		{
			DataPartition* dataPart;           
			Slice*         currSlice = img->currentSlice ;
			int*            bitCount  = currMB->bitcounter;
			int             no_bits   = 0;
			CheckAvailabilityOfNeighborsAEC();
			dataPart = &(currSlice->partArr[0]);
			currSE->writing=writeRunLengthInfo2Buffer_AEC;
			dataPart->writeSyntaxElement(currSE,dataPart);
		}
		rlc_bits=currSE->len;
		currMB->bitcounter[BITS_MB_MODE]+=rlc_bits;
		img->cod_counter = 0;
	}

}

/*
*************************************************************************
* Function: Checks the availability of neighboring macroblocks of
the current macroblock for prediction and context determination;
marks the unavailable MBs for intra prediction in the
past of the current MB are checked.
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void CheckAvailabilityOfNeighbors()
{
	int i,j;

	//const int mb_width = input->img_width/MB_BLOCK_SIZE;
	const int mb_width = img->width/MB_BLOCK_SIZE; 
	const int mb_nr    = img->current_mb_nr;
	Macroblock *currMB = &img->mb_data[mb_nr];
	int   pix_x   = img->pix_x;  
	int   tmp_x   = img->block_x;
	int   tmp_y   = img->block_y;
	int   block_x = img->block_x/2;
	int   pix_y   = img->pix_y;   
	int   block_y = img->block_y/2;
	int   remove_prediction;
    int b4_x, b4_y;
	img->block_x = block_x;
	img->block_y = block_y;
    b4_x = block_x * 2;
    b4_y = block_y * 2;

	// mark all neighbors as unavailable
	for (i=0; i<3; i++)
		for (j=0; j<3; j++)
		{
			img->mb_data[mb_nr].mb_available[i][j]=NULL;
		}

		img->mb_data[mb_nr].mb_available[1][1]=currMB; // current MB

		// Check MB to the left
		if(pix_x >= MB_BLOCK_SIZE)
		{

			remove_prediction = currMB->slice_nr != img->mb_data[mb_nr-1].slice_nr;

			if (!remove_prediction)
			{
				currMB->mb_available[1][0]=&(img->mb_data[mb_nr-1]);
			}
		}

		// Check MB above
		if(pix_y >= MB_BLOCK_SIZE) 
		{

			remove_prediction = currMB->slice_nr != img->mb_data[mb_nr-mb_width].slice_nr;

			if (!remove_prediction)
			{  
				currMB->mb_available[0][1]=&(img->mb_data[mb_nr-mb_width]);
			}
		}

		// Check MB left above
		if(pix_x >= MB_BLOCK_SIZE && pix_y >= MB_BLOCK_SIZE )
		{

			remove_prediction = currMB->slice_nr != img->mb_data[mb_nr-mb_width-1].slice_nr;

			if (!remove_prediction)
			{
				currMB->mb_available[0][0]=&(img->mb_data[mb_nr-mb_width-1]);
			}
		}

		// Check MB right above
		if(pix_y >= MB_BLOCK_SIZE && img->pix_x < (img->width-MB_BLOCK_SIZE ))
		{

			if(currMB->slice_nr == img->mb_data[mb_nr-mb_width+1].slice_nr)
				currMB->mb_available[0][2]=&(img->mb_data[mb_nr-mb_width+1]);

		}

		img->block_x = tmp_x;
		img->block_y = tmp_y;

		currMB->mbAddrA = mb_nr - 1;
		currMB->mbAddrB = mb_nr - img->PicWidthInMbs;
		currMB->mbAddrC = mb_nr - img->PicWidthInMbs + 1;
		currMB->mbAddrD = mb_nr - img->PicWidthInMbs - 1;
		currMB->mbAvailA = (currMB->mb_available[1][0]!=NULL)?1:0;
		currMB->mbAvailB = (currMB->mb_available[0][1]!=NULL)?1:0;
		currMB->mbAvailC = (currMB->mb_available[0][2]!=NULL)?1:0;
		currMB->mbAvailD = (currMB->mb_available[0][0]!=NULL)?1:0;
}

/*
*************************************************************************
* Function:Predict one component of a 4x4 Luma block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
void OneComponentLumaPrediction4x4 (int*   mpred,      //  --> array of prediction values (row by row)
									int    pic_pix_x,  // <--  absolute horizontal coordinate of 4x4 block
									int    pic_pix_y,  // <--  absolute vertical   coordinate of 4x4 block
									int*   mv,         // <--  motion vector
									int    ref)        // <--  reference frame (0.. / -1:backward)
{
	int incr=0;/*lgp*13*/
	pel_t* ref_pic;
	int     pix_add = 4;
	int     j0      = (pic_pix_y << 2) + mv[1], j1=j0+pix_add, j2=j1+pix_add, j3=j2+pix_add;
	int     i0      = (pic_pix_x << 2) + mv[0], i1=i0+pix_add, i2=i1+pix_add, i3=i2+pix_add;
	int     i,j;

	pel_t (*get_pel) (pel_t*, int, int) = UMVPelY_14;

	mv_out_of_range *= check_mv_range(mv[0], mv[1], pic_pix_x, pic_pix_y, 5);

	incr = 1;

	ref_pic = img->type == B_IMG ? mref[ref + incr] : mref[ref];

	for(j=0;j<4;j++)
	{
		for(i=0;i<4;i++)
		{
			*mpred++ = get_pel (ref_pic, j0+pix_add*j, i0+pix_add*i);
		}
	}
}



/*
*************************************************************************
* Function:Predict one component of a 8x8 Luma block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void OneComponentLumaPrediction8x8(int*   mpred,      //  --> array of prediction values (row by row)
								   int    pic_pix_x,  // <--  absolute horizontal coordinate of 8x8 block
								   int    pic_pix_y,  // <--  absolute vertical   coordinate of 8x8 block
								   int*   mv,         // <--  motion vector
								   int    ref)        // <--  reference frame (0.. / -1:backward)
{
	int incr=1;/*lgp*13*/
	pel_t* ref_pic;
	int     pix_add = 4;
	int     j0      = (pic_pix_y << 2) + mv[1], j1=j0+pix_add, j2=j1+pix_add, j3=j2+pix_add;
	int     i0      = (pic_pix_x << 2) + mv[0], i1=i0+pix_add, i2=i1+pix_add, i3=i2+pix_add;
	int     i,j;

	pel_t (*get_pel) (pel_t*, int, int) = UMVPelY_14;

	mv_out_of_range *= check_mv_range(mv[0], mv[1], pic_pix_x, pic_pix_y, 4);		

	ref_pic = img->type == B_IMG ? mref[ref + incr] : mref[ref];

	for(j=0;j<8;j++)
	{
		for(i=0;i<8;i++)
		{
			*mpred++ = get_pel (ref_pic, j0+pix_add*j, i0+pix_add*i);
		}
	}
}
/*
*************************************************************************
* Function:Predict one 8x8 Luma block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void
	LumaPrediction8x8 (int  block_x,    // <--  relative horizontal block coordinate of 8x8 block
						int  block_y,    // <--  relative vertical   block coordinate of 8x8 block
						int  fw_mode,    // <--  forward  prediction mode (1-7, 0=DIRECT if bw_mode=0)
						int  bw_mode,    // <--  backward prediction mode (1-7, 0=DIRECT if fw_mode=0)
						int  fw_ref,      // <--  reference frame for forward prediction (-1: Intra8x8 pred. with fw_mode)
						int  bw_ref,
						int pdir
	)    
{
	static int fw_pred[64];
	static int bw_pred[64];
	int  i, j;
	int  block_x8  = block_x+8;//qyu 4->8
	int  block_y8  = block_y+8;//qyu 4->8
	int  pic_pix_x = img->pix_x + block_x;
	int  pic_pix_y = img->pix_y + block_y;
	int  bx        = block_x >> 3;
	int  by        = block_y >> 3;
	int* fpred     = fw_pred;
	int* bpred     = bw_pred;
	int  direct    = (fw_mode == 0 && bw_mode == 0 && (img->type==B_IMG));
	int  skipped   = (fw_mode == 0 && bw_mode == 0 && (img->type!=B_IMG));
	int  *****fmv_array = (fw_mode && bw_mode)?img->all_omv:img->all_mv;    // For MB level frame/field coding
	int  *****bmv_array = img->all_bmv;   // For MB level frame/field coding
	int bw_ref_num ;
	int fw_ref_num ;

	int *****fbimv_array = img->all_bimv;
	if((img->type == P_IMG) && (pdir == 3))
	{
		fmv_array = img->all_Lbimv;
	}

	if (direct)    
	{
		fw_ref= 0;//max(refFrArr[ipdirect_y][ipdirect_x],0);
		bw_ref= 0;//min(refFrArr[ipdirect_y][ipdirect_x],0);
	}


	direct_mode = direct;

	if (fw_mode ||(direct && (fw_ref !=-1) )|| skipped)
	{
		OneComponentLumaPrediction8x8 (fw_pred, pic_pix_x, pic_pix_y, fmv_array [bx][by][fw_ref][fw_mode], (direct ?0:fw_ref));
	}

	if((img->type == P_IMG) && fw_mode &&(fw_ref != -1) && (pdir == 3))
	{
		OneComponentLumaPrediction8x8(bw_pred, pic_pix_x, pic_pix_y, fbimv_array [bx][by][fw_ref][fw_mode], fw_ref);
	}

	if (bw_mode || (direct && (bw_ref !=-1) ))
	{
		int delta_P,TRp,DistanceIndexFw,DistanceIndexBw,refframe,delta_PB;
		int mv[2];
		refframe = fw_ref;
		delta_P = 2*(img->imgtr_next_P_frm - img->imgtr_last_P_frm);
		delta_P = (delta_P + 512)%512;   
		TRp = (refframe+1)*delta_P;  //the lates backward reference

		delta_PB = 2*(picture_distance - img->imgtr_last_P_frm);  
		TRp  = (TRp + 512)%512;
		delta_PB = (delta_PB + 512)%512;

		DistanceIndexFw = delta_PB;	    

		DistanceIndexBw    = (TRp - DistanceIndexFw+512)%512; 

		mv[0] = - ((fmv_array[bx][by][fw_ref][fw_mode][0]*DistanceIndexBw*(512/DistanceIndexFw)+256)>>9);
		mv[1] = - ((fmv_array[bx][by][fw_ref][fw_mode][1]*DistanceIndexBw*(512/DistanceIndexFw)+256)>>9);
		if(fw_mode && bw_mode)
			OneComponentLumaPrediction8x8 (bw_pred, pic_pix_x, pic_pix_y, mv, (-1-bw_ref));
		else
			OneComponentLumaPrediction8x8 (bw_pred, pic_pix_x, pic_pix_y, bmv_array[bx][by][bw_ref][bw_mode], (-1-bw_ref));
	}

	if (direct || (fw_mode && bw_mode))
	{	

		fw_ref_num = fw_ref;  
		bw_ref_num = bw_ref+1; 

		for(j=block_y; j<block_y8; j++)
			for (i=block_x; i<block_x8; i++){
				img->mpr[i][j] = (*fpred + *bpred + 1) / 2;

				fpred++;
				bpred++;
			}
	}
	else if ((img->type == P_IMG) && fw_mode && (fw_ref != -1) &&(pdir == 3))
	{
		for(j=block_y; j<block_y8; j++)
			for (i=block_x; i<block_x8; i++){
				img->mpr[i][j] = (*fpred + *bpred + 1) / 2;

				fpred++;
				bpred++;
			}
	}
	else if (fw_mode || skipped)  //P and B one direction fw 
	{

		for(j=block_y; j<block_y8; j++)
			for (i=block_x; i<block_x8; i++){
				img->mpr[i][j] = *fpred;
				fpred++;
			}
	}
	else  //B one direction bw
	{
		for(j=block_y; j<block_y8; j++)
			for (i=block_x; i<block_x8; i++){
				img->mpr[i][j] = *bpred;
				bpred++;
			}
	}
}


/*
*************************************************************************
* Function:Residual Coding of an 8x8 Luma block (not for intra)
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int                                           //  ==> coefficient cost
	LumaResidualCoding8x8 (int  *cbp,         //  --> cbp (updated according to processed 8x8 luminance block)
						   int  block8x8,     // <--  block number of 8x8 block
						   int  fw_mode,      // <--  forward  prediction mode (1-7, 0=DIRECT)
						   int  bw_mode,      // <--  backward prediction mode (1-7, 0=DIRECT)
						   int  fw_refframe,  // <--  reference frame for forward prediction
						   int  bw_refframe   // <--  reference frame for backward prediction
#ifdef RDO_Q
						   ,double lambda
#endif
	)
{
	int     pic_pix_y, pic_pix_x, i, j;//qyu delete , cbp_blk_mask;
	int    coeff_cost = 0;
	int    mb_y       = (block8x8 / 2) << 3;
	int    mb_x       = (block8x8 % 2) << 3;
	int    cbp_mask   = 1 << block8x8;
	int    scrFlag = 0;                // 0=noSCR, 1=strongSCR, 2=jmSCR
	uchar_t* imgY_original = imgY_org;
	int  pix_x    = img->pix_x;
	int  pix_y    = img->pix_y;
	Macroblock* currMB = &img->mb_data[img->current_mb_nr];
	int    direct    = (fw_mode == 0 && bw_mode == 0 && (img->type==B_IMG));
	int    skipped   = (fw_mode == 0 && bw_mode == 0 && (img->type!=B_IMG));
	int    curr_blk[MB_BLOCK_SIZE*MB_BLOCK_SIZE]; // IVC 8x8 pred.error buffer 

	if (img->type==B_IMG)
		scrFlag = 1;

	pic_pix_y = pix_y + mb_y;
	pic_pix_x = pix_x + mb_x;

	LumaPrediction8x8(mb_x, mb_y, fw_mode, bw_mode, fw_refframe, bw_refframe, currMB->b8pdir[block8x8]);

	//===== get displaced frame difference ======
    for (j=0; j<8; j++) {
        for (i=0; i<8; i++) {
			img->m7[i][j] = curr_blk[j*8+i] = imgY_original[(pic_pix_y + j) * (img->width) + pic_pix_x + i] - img->mpr[i + mb_x][j + mb_y];
        }
    }


#ifdef B_DIRECT_REMOVE
    if((!skipped)&&(!direct))
#else
    if (!skipped)
#endif
    {
        transform_B8(curr_blk, 8);
        coeff_cost = scanquant_B8(img->qp-MIN_QP, 0, block8x8, 0, curr_blk, scrFlag, cbp
#ifdef RDO_Q
            ,lambda
#endif
            ,8);	
    }

    if (!skipped && coeff_cost <= _LUMA_COEFF_COST_) {
        coeff_cost  = 0;
        (*cbp) &= 0xFFFFFFFF ^ (1 << block8x8);

        for (i=mb_x; i<mb_x+8; i++) {
            for (j=mb_y; j<mb_y+8; j++) {
				imgY[(img->pix_y + j)*(img->iStride) + img->pix_x + i] = img->mpr[i][j];
            }
        }
    }

    return coeff_cost;
}



/*
*************************************************************************
* Function:Set mode parameters and reference frames for an 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void
	SetModesAndRefframe (int b8, int* fw_mode, int* bw_mode, int* fw_ref, int* bw_ref)
{
	Macroblock* currMB = &img->mb_data[img->current_mb_nr];
	int         j      = (b8/2);
	int         i      = (b8%2);
	int**     frefarr = refFrArr;   // For MB level field/frame coding
	int**     fw_refarr = fw_refFrArr;  // For MB level field/frame coding
	int**     bw_refarr = bw_refFrArr;  // For MB level field/frame coding
	int     block_x = img->block_x; 
	int     block_y = img->block_y; // For MB level field/frame coding

	*fw_mode = *bw_mode = *fw_ref = *bw_ref = -1;

	if (img->type!=B_IMG)
	{
		*fw_ref = frefarr[(block_y>>1)+j][(block_x>>1)+i];
		*bw_ref = 0;
		*bw_mode  = 0;
		*fw_mode  = currMB->b8mode[b8];
	}
	else
	{
		if (currMB->b8pdir[b8]==-1)
		{
			*fw_ref   = -1;
			*bw_ref   = -1;
			*fw_mode  =  0;
			*bw_mode  =  0;
		}
		else if (currMB->b8pdir[b8]==0)
		{
			*fw_ref   = fw_refarr[(block_y>>1)+j][(block_x>>1)+i];
			*bw_ref   = 0;
			*fw_mode  = currMB->b8mode[b8];
			*bw_mode  = 0;
		}
		else if (currMB->b8pdir[b8]==1)
		{
			*fw_ref   = 0;
			*bw_ref   = bw_refarr[(block_y>>1)+j][(block_x>>1)+i];
			*fw_mode  = 0;
			*bw_mode  = currMB->b8mode[b8];
		}
		else
		{
			*fw_ref   = fw_refarr[(block_y>>1)+j][(block_x>>1)+i];
			*bw_ref   = bw_refarr[(block_y>>1)+j][(block_x>>1)+i];
			*fw_mode  = currMB->b8mode[b8];
			*bw_mode  = currMB->b8mode[b8];

			if (currMB->b8mode[b8]==0) // direct
			{

				if (img->type==B_IMG)
				{
					//sw
					*fw_ref = 0;// max(0,frefarr[(block_y>>1)+j][(block_x>>1)+i]);
					*bw_ref = 0;
				}
				else
				{
					*fw_ref = max(0,frefarr[(block_y>>1)+j][(block_x>>1)+i]);
					*bw_ref = 0;
				}
			}
		}
	}
}

/*
*************************************************************************
* Function:Residual Coding of a Luma macroblock (not for intra)
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/


void LumaResidualCoding (
#ifdef RDO_Q
	double lambda
#endif
	)
{
	int i,j,block8x8;
	int fw_mode, bw_mode, refframe, bw_ref;
	int sum_cnt_nonz;
	Macroblock *currMB = &img->mb_data[img->current_mb_nr];
	int incr_y=1,off_y=0;
	uchar_t* imgY_original = imgY_org;
    int    curr_blk[MB_BLOCK_SIZE*MB_BLOCK_SIZE]; // IVC 8x8 pred.error buffer 
    int    direct, skipped;
    int    scrFlag = (img->type==B_IMG);                // 0=noSCR, 1=strongSCR, 2=jmSCR

	currMB->cbp     = 0 ;
	sum_cnt_nonz    = 0 ;

	for (block8x8=0; block8x8<4; block8x8++)
	{
        int    pic_pix_y, pic_pix_x, i, j;//qyu delete , cbp_blk_mask;
        
        int    mb_y       = (block8x8 / 2) << 3;
        int    mb_x       = (block8x8 % 2) << 3;
        int    coeff_cost = 0;
        int  pix_x    = img->pix_x;
        int  pix_y    = img->pix_y;
        Macroblock* currMB = &img->mb_data[img->current_mb_nr];
        
        SetModesAndRefframe (block8x8, &fw_mode, &bw_mode, &refframe, &bw_ref);

        direct    = (fw_mode == 0 && bw_mode == 0 && (img->type==B_IMG));
        skipped   = (fw_mode == 0 && bw_mode == 0 && (img->type!=B_IMG));

        pic_pix_y = pix_y + mb_y;
        pic_pix_x = pix_x + mb_x;

        LumaPrediction8x8(mb_x, mb_y, fw_mode, bw_mode, refframe, bw_ref, currMB->b8pdir[block8x8]);

        if (currMB->trans_type == TRANS_NxN) {
            for (j=0; j<8; j++) {
                for (i=0; i<8; i++) {
					img->m7[i][j] = curr_blk[j*8+i] = imgY_original[(pic_pix_y + j)*(img->width) + pic_pix_x + i] - img->mpr[i + mb_x][j + mb_y];
                }
            }

            if((!skipped)&&(!direct)) {
                transform_B8(curr_blk, 8);
                coeff_cost = scanquant_B8   (img->qp-MIN_QP, 0, block8x8, 0, curr_blk, scrFlag, &currMB->cbp ,lambda ,8);	
            }

            if (coeff_cost <= _LUMA_COEFF_COST_) {
                coeff_cost = 0;
                currMB->cbp &= 0xFFFFFFFF ^ (0xF << (block8x8*4));

                for (i=mb_x; i<mb_x+8; i++) {
                    for (j=mb_y; j<mb_y+8; j++) {
						imgY[(img->pix_y + j)*(img->iStride) + img->pix_x + i] = img->mpr[i][j];
                    }
                }
            }

            sum_cnt_nonz += coeff_cost;
        }
	}

    if (currMB->trans_type == TRANS_2Nx2N) {
        for (j = 0; j < 16; j++) {
            for (i = 0; i < 16; i++) {
				img->m7[i][j] = curr_blk[j*16+i] = imgY_original[(img->pix_y + j)*(img->width) + img->pix_x + i] - img->mpr[i][j];
            }
        }

        if((!skipped)&&(!direct)) {
            transform_B8(curr_blk, 16);
            sum_cnt_nonz = scanquant_B8   (img->qp-MIN_QP, 0, 0, 0, curr_blk, scrFlag, &currMB->cbp ,lambda ,16);	
        }

        if (sum_cnt_nonz <= 5) {
            currMB->cbp     &=  0xffff0000;

            for (i=0; i<16; i++) {
                for (j=0; j<16; j++) {
					imgY[(img->pix_y + j)*(img->iStride) + img->pix_x + i] = img->mpr[i][j];
                }
            }
        }
        if (currMB->cbp & 0xffff) {
            currMB->cbp |= 0xffff;
        }
    } else {
        if (sum_cnt_nonz <= 5)
        {
            currMB->cbp     &= 0xffff0000 ;
            for (i=0; i < MB_BLOCK_SIZE; i++)
            {
                for (j=0; j < MB_BLOCK_SIZE; j++)
                {
					imgY[(img->pix_y + j)*(img->iStride) + img->pix_x + i] = img->mpr[i][j];
                }
            }
        }
    }
}

/*
*************************************************************************
* Function: Predict one component of a chroma 4x4 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void OneComponentChromaPrediction4x4 (int*     mpred,      //  --> array to store prediction values
									  int      pix_c_x,    // <--  horizontal pixel coordinate of 4x4 block
									  int      pix_c_y,    // <--  vertical   pixel coordinate of 4x4 block
									  int***** mv,         // <--  motion vector array
									  int      ref,        // <--  reference frame parameter (0.../ -1: backward)
									  int      blocktype,  // <--  block type
									  int      uv,
									  int      directforword)         // <--  chroma component
{
	int     i, j, ii, jj;
	int     incr;
	int*    mvb;
	int     refframe  = (ref<0 ?      0 :    ref);
	pel_t*  refimage;
	int     je        = pix_c_y + 4;
	int     ie        = pix_c_x + 4;
	int     f1        = 8 , f2=f1-1, f3=f1*f1, f4=f3>>1;
	int     s1        = 3;
	int     img_pic_c_x = img->pix_c_x;
	int     img_pic_c_y = img->pix_c_y;
	int     scale   = 1;
	int     fpred = ref < 0 ? 0: 1;

	incr = 1;
	ref = (img->type==B_IMG) ? ref+incr : ref;

	refimage = mcef[ref][uv];

	for (j=pix_c_y; j<je; j++)
		for (i=pix_c_x; i<ie; i++)
		{
            int posx, posy;
            int curx, cury;
            int x0, x1, x2, x3;
            int y0, y1, y2, y3;
            int val;
            static const int COEF[8][4] = {
                { 0, 64, 0, 0 },
                { -4, 62, 6, 0 },
                { -6, 56, 15, -1 },
                { -5, 47, 25, -3 },
                { -4, 36, 36, -4 },
                { -3, 25, 47, -5 },
                { -1, 15, 56, -6 },
                { 0, 6, 62, -4 }
            };
			mvb  = mv [(i-img_pic_c_x)>>2][(j-img_pic_c_y)>>2][refframe][blocktype];
			ii   = (i<<s1) + mvb[0];
			jj   = (j<<s1) + mvb[1];

            posx = (ii & 7);
            posy = (jj & 7);
			curx = ii >> 3;
			cury = jj >> 3;

            if (posy == 0) {
                x0 = max(0, min(img->width_cr - 1, curx - 1));
                x1 = max(0, min(img->width_cr - 1, curx - 0));
                x2 = max(0, min(img->width_cr - 1, curx + 1));
                x3 = max(0, min(img->width_cr - 1, curx + 2));
                y0 = y1 = y2 = y3 = max(0, min(img->height_cr - 1, cury));

				val = refimage[y0*img->iStrideC + x0] * COEF[posx][0] +
					refimage[y1*img->iStrideC + x1] * COEF[posx][1] +
					refimage[y2*img->iStrideC + x2] * COEF[posx][2] +
					refimage[y3*img->iStrideC + x3] * COEF[posx][3];
            }
            else if (posx == 0) {
                y0  = max(0, min(img->height_cr - 1, cury - 1));
                y1  = max(0, min(img->height_cr - 1, cury - 0));
                y2  = max(0, min(img->height_cr - 1, cury + 1));
                y3  = max(0, min(img->height_cr - 1, cury + 2));
                x0  = x1 = x2 = x3 = max(0, min(img->width_cr - 1, curx));

				val = refimage[y0*img->iStrideC + x0] * COEF[posy][0] +
					refimage[y1*img->iStrideC + x1] * COEF[posy][1] +
					refimage[y2*img->iStrideC + x2] * COEF[posy][2] +
					refimage[y3*img->iStrideC + x3] * COEF[posy][3];
            }
            else {
                int tmp[4], line;
                for (line = -1; line < 3; line++) {
                    x0 = max(0, min(img->width_cr - 1, curx - 1));
                    x1 = max(0, min(img->width_cr - 1, curx - 0));
                    x2 = max(0, min(img->width_cr - 1, curx + 1));
                    x3 = max(0, min(img->width_cr - 1, curx + 2));
                    y0 = y1 = y2 = y3 = max(0, min(img->height_cr - 1, cury + line));

					tmp[line + 1] = refimage[y0*img->iStrideC + x0] * COEF[posx][0] +
						refimage[y1*img->iStrideC + x1] * COEF[posx][1] +
						refimage[y2*img->iStrideC + x2] * COEF[posx][2] +
						refimage[y3*img->iStrideC + x3] * COEF[posx][3];
                }

                val = (tmp[0] * COEF[posy][0] +
                    tmp[1] * COEF[posy][1] +
                    tmp[2] * COEF[posy][2] +
                    tmp[3] * COEF[posy][3] + 32) / 64;
            }

            *mpred++ = Clip1((val + f4) / f3);

		}
}


/*
*************************************************************************
* Function:Predict one component of a chroma 4x4 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void
	OneComponentChromaPrediction4x4_dir (int*     mpred,      //  --> array to store prediction values
	int      pix_c_x,    // <--  horizontal pixel coordinate of 4x4 block
	int      pix_c_y,    // <--  vertical   pixel coordinate of 4x4 block
	int***** mv,         // <--  motion vector array
	int      ref,        // <--  reference frame parameter (0.../ -1: backward)
	int      blocktype,  // <--  block type
	int      uv,
	int		refframe
	)
{
	int     i, j, ii, jj;
	int     incr;
	int*    mvb;
	//int     refframe  = (ref<0 ?      0 :    ref);
	pel_t* refimage;
	int     je        = pix_c_y + 4;
	int     ie        = pix_c_x + 4;
	int     f1        = 8 , f2=f1-1, f3=f1*f1, f4=f3>>1;
	int     s1        = 3;
	int     img_pic_c_y = img->pix_c_y;


	incr = 1;
	ref = (img->type==B_IMG) ? ref+incr : ref;
	refimage = mcef[ref][uv];


	for (j=pix_c_y; j<je; j++)
		for (i=pix_c_x; i<ie; i++)
		{
            int delta_P, TRp, DistanceIndexFw, DistanceIndexBw, delta_PB;
            int posx, posy;
            int curx, cury;
            int x0, x1, x2, x3;
            int y0, y1, y2, y3;
            int val;
            static const int COEF[8][4] = {
                { 0, 64, 0, 0 },
                { -4, 62, 6, 0 },
                { -6, 56, 15, -1 },
                { -5, 47, 25, -3 },
                { -4, 36, 36, -4 },
                { -3, 25, 47, -5 },
                { -1, 15, 56, -6 },
                { 0, 6, 62, -4 }
            };

            mvb = mv[(i - img->pix_c_x) >> 2][(j - img_pic_c_y) >> 2][refframe][blocktype];
            delta_P = 2 * (img->imgtr_next_P_frm - img->imgtr_last_P_frm);
            delta_P = (delta_P + 512) % 512;
            TRp = refframe == 0 ? delta_P : (2 * (img->imgtr_next_P_frm - img->imgtr_last_prev_P_frm) + 512) % 512;
            delta_PB = 2 * (picture_distance - img->imgtr_last_P_frm);
            TRp = (TRp + 512) % 512;
            delta_PB = (delta_PB + 512) % 512;
            DistanceIndexFw = delta_PB;
            DistanceIndexBw = (TRp - DistanceIndexFw + 512) % 512;
            ii = (i << s1) - ((mvb[0] * DistanceIndexBw*(512 / DistanceIndexFw) + 256) >> 9);
            jj = (j << s1) - ((mvb[1] * DistanceIndexBw*(512 / DistanceIndexFw) + 256) >> 9);

            posx = (ii & 7);
            posy = (jj & 7);
			curx = ii >> 3;
			cury = jj >> 3;

            if (posy == 0) {
                x0 = max(0, min(img->width_cr - 1, curx - 1));
                x1 = max(0, min(img->width_cr - 1, curx - 0));
                x2 = max(0, min(img->width_cr - 1, curx + 1));
                x3 = max(0, min(img->width_cr - 1, curx + 2));
                y0 = y1 = y2 = y3 = max(0, min(img->height_cr - 1, cury));

				val = refimage[y0*img->iStrideC + x0] * COEF[posx][0] +
					refimage[y1*img->iStrideC + x1] * COEF[posx][1] +
					refimage[y2*img->iStrideC + x2] * COEF[posx][2] +
					refimage[y3*img->iStrideC + x3] * COEF[posx][3];
            }
            else if (posx == 0) {
                y0 = max(0, min(img->height_cr - 1, cury - 1));
                y1 = max(0, min(img->height_cr - 1, cury - 0));
                y2 = max(0, min(img->height_cr - 1, cury + 1));
                y3 = max(0, min(img->height_cr - 1, cury + 2));
                x0 = x1 = x2 = x3 = max(0, min(img->width_cr - 1, curx));

				val = refimage[y0*img->iStrideC + x0] * COEF[posy][0] +
					refimage[y1*img->iStrideC + x1] * COEF[posy][1] +
					refimage[y2*img->iStrideC + x2] * COEF[posy][2] +
					refimage[y3*img->iStrideC + x3] * COEF[posy][3];
            }
            else {
                int tmp[4], line;
                for (line = -1; line < 3; line++) {
                    x0 = max(0, min(img->width_cr - 1, curx - 1));
                    x1 = max(0, min(img->width_cr - 1, curx - 0));
                    x2 = max(0, min(img->width_cr - 1, curx + 1));
                    x3 = max(0, min(img->width_cr - 1, curx + 2));
                    y0 = y1 = y2 = y3 = max(0, min(img->height_cr - 1, cury + line));
            
					tmp[line + 1] = refimage[y0*img->iStrideC + x0] * COEF[posx][0] +
						refimage[y1*img->iStrideC + x1] * COEF[posx][1] +
						refimage[y2*img->iStrideC + x2] * COEF[posx][2] +
						refimage[y3*img->iStrideC + x3] * COEF[posx][3];
                }

                val = (tmp[0] * COEF[posy][0] +
                    tmp[1] * COEF[posy][1] +
                    tmp[2] * COEF[posy][2] +
                    tmp[3] * COEF[posy][3] + 32) / 64;
            }

            *mpred++ = Clip1((val + f4) / f3);
		}
}

/*
*************************************************************************
* Function:Predict an intra chroma 4x4 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void IntraChromaPrediction4x4 (int  uv,       // <-- colour component
							   int  block_x,  // <-- relative horizontal block coordinate of 4x4 block
							   int  block_y)  // <-- relative vertical   block coordinate of 4x4 block
{
	int mode = img->mb_data[img->current_mb_nr].c_ipred_mode;
	int i, j;

	//===== prediction =====
	for (j = block_y; j < block_y + 4; j++)
	{
		for (i = block_x; i < block_x + 4; i++)
		{
			img->mpr[i][j] = img->mprr_c[uv][mode][j * 16 + i];
		}
	}
		
}

/*
*************************************************************************
* Function:Predict one chroma 4x4 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void
	ChromaPrediction4x4 (int  uv,           // <-- colour component
	int  block_x,      // <-- relative horizontal block coordinate of 4x4 block
	int  block_y,      // <-- relative vertical   block coordinate of 4x4 block
	int  fw_mode,      // <-- forward  prediction mode (1-7, 0=DIRECT if bw_mode=0)
	int  bw_mode,      // <-- backward prediction mode (1-7, 0=DIRECT if fw_mode=0)
	int  fw_ref_frame, // <-- reference frame for forward prediction (if (<0) -> intra prediction)
	int  bw_ref_frame,
	int pdir
	) // <-- reference frame for backward prediction 
{
	static int fw_pred[16];
	static int bw_pred[16];

	int  i, j;
	int  block_x4  = block_x+4;
	int  block_y4  = block_y+4;
	int  pic_pix_x = img->pix_c_x + block_x;
	int  pic_pix_y = img->pix_c_y + block_y;
	int* fpred     = fw_pred;
	int* bpred     = bw_pred;
	int  by ;
	int  bx = (block_x >>2);

	int  direct    = (fw_mode == 0 && bw_mode == 0 && (img->type==B_IMG));

	int  skipped   = (fw_mode == 0 && bw_mode == 0 && (img->type!=B_IMG));
	int  *****fmv_array = (fw_mode && bw_mode)?img->all_omv:img->all_mv;  

	int***** bmv_array = img->all_bmv;
	int fw_ref_idx, bw_ref_idx;

	int directforward = (img->type==B_IMG && fw_mode==0);

	int***** bimv_array = img->all_bimv;
	if((img->type == P_IMG) && (pdir == 3))
	{
		fmv_array = img->all_Lbimv;
	}

	by= (block_y >>2);

	direct_mode = direct;

	//===== INTRA PREDICTION =====
	if (fw_ref_frame < 0)
	{
		IntraChromaPrediction4x4 (uv, block_x, block_y);
		return;
	}

	if (direct)    
	{
		fw_ref_frame= 0;
		bw_ref_frame= 0;
	}

	fw_ref_idx = fw_ref_frame;
	bw_ref_idx = bw_ref_frame;

	//===== INTER PREDICTION =====
	if (fw_mode || (direct && (fw_ref_frame!=-1)) || skipped)
	{
		OneComponentChromaPrediction4x4 (fw_pred, pic_pix_x, pic_pix_y, fmv_array , (directforward ?0 :fw_ref_frame), fw_mode, uv, (directforward ?1 :0));
	}

	if((img->type == P_IMG) && fw_mode && (fw_ref_frame != -1) && (pdir == 3))
	{
		OneComponentChromaPrediction4x4 (bw_pred, pic_pix_x, pic_pix_y, bimv_array , (directforward ?0 :fw_ref_frame), fw_mode, uv, (directforward ?1 :0));
	}

	if (bw_mode || (direct && (bw_ref_frame!=-1))) 
	{
		if(fw_mode && bw_mode)
			OneComponentChromaPrediction4x4_dir (bw_pred, pic_pix_x, pic_pix_y, fmv_array,  -1, bw_mode, uv,fw_ref_frame);
		else
			OneComponentChromaPrediction4x4 (bw_pred, pic_pix_x, pic_pix_y, bmv_array,  -1, bw_mode, uv,0);
	}

	if (direct || (fw_mode && bw_mode))
	{
		for (j=block_y; j<block_y4; j++)
			for (i=block_x; i<block_x4; i++){
				img->mpr[i][j] = (*fpred + *bpred + 1) / 2;

				fpred++ ; 
				bpred++ ;
			}
	}
	else if ((img->type == P_IMG) && fw_mode && (fw_ref_frame != -1) && (pdir == 3))
	{
		for (j=block_y; j<block_y4; j++)
			for (i=block_x; i<block_x4; i++){
				img->mpr[i][j] = (*fpred + *bpred + 1) / 2;

				fpred++ ; 
				bpred++ ;
			}
	}
	else if (fw_mode || skipped)  //P and B one direction fw
	{

		for (j=block_y; j<block_y4; j++)
			for (i=block_x; i<block_x4; i++){  
				img->mpr[i][j] = *fpred;
				fpred++;
			}
	}
	else  //B bw 
	{

		for (j=block_y; j<block_y4; j++)
			for (i=block_x; i<block_x4; i++){  
				img->mpr[i][j] = *bpred;

				bpred++;
			}
	}
}

/*
*************************************************************************
* Function:Chroma residual coding for an macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void ChromaResidualCoding (int* cr_cbp
#ifdef RDO_Q
	,double lambda
#endif
	)
{
	int   uv, block8, block_y, block_x, j, i;
	int   fw_mode, bw_mode, refframe;
	int   skipped = (img->mb_data[img->current_mb_nr].mb_type == 0 && img->type == P_IMG);
	int   incr = 1, offset = 0;
	int   incr_x = 1, offset_x = 0; 
	int   bw_ref;
	int   tmp_block_88[MB_BLOCK_SIZE*MB_BLOCK_SIZE]; 
	int   tmp_block[2][8][8];
	int   tmp_mpr[2][8][8];
	int   incr_y=1,off_y=0;

	Macroblock *currMB   = &img->mb_data[img->current_mb_nr];
	int IntraPrediction=IS_INTRA (currMB);
	int  direct;

	int   block8x8_idx[4][4] =   
	{ {0, 1, 0, 0}, 
	{0, 1, 0, 0}, 
	{2, 3, 0, 0},
	{2, 3, 0, 0}  
	};  

    for (*cr_cbp = 0, uv = 0; uv < 2; uv++)
    {
        //===== prediction of chrominance blocks ===d==
        block8 = 0;
        for (block_y =/*0*/4 * (0 / 2); block_y < 8; block_y += 4){
            for (block_x = 0; block_x < 8; block_x += 4, block8++)
            {
                block8 = (block_y / 4) * 2 + block_x / 4;

                SetModesAndRefframe(block8, &fw_mode, &bw_mode, &refframe, &bw_ref);
                ChromaPrediction4x4(uv, block_x, block_y, fw_mode, bw_mode, refframe, bw_ref, currMB->b8pdir[block8]);

                direct = (fw_mode == 0 && bw_mode == 0 && (img->type == B_IMG));

                if (skipped || img->NoResidueDirect)
                {
                    for (j = 0; j < 4; j++)
                    for (i = block_x; i < block_x + 4; i++)
                    {
						if (0 == uv)
						{
							imgU[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->iStrideC) + img->pix_c_x + i] = img->mpr[i][block_y + j];
						}
						else
						{
							imgV[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->iStrideC) + img->pix_c_x + i] = img->mpr[i][block_y + j];
						}
                        
                    }
                }
                else
                for (j = 0; j < 4; j++)
                for (i = block_x; i < block_x + 4; i++)
                {
                    tmp_mpr[uv][i][block_y + j] = img->mpr[i][block_y + j];

					if (0 == uv)
					{
						tmp_block[uv][block_y + j][i] = imgU_org[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->width_cr) + img->pix_c_x + i] - img->mpr[i][block_y + j];
						img->m7[i][block_y + j] = imgU_org[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->width_cr) + img->pix_c_x + i] - img->mpr[i][block_y + j];
					}
					else
					{
						tmp_block[uv][block_y + j][i] = imgV_org[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->width_cr) + img->pix_c_x + i] - img->mpr[i][block_y + j];
						img->m7[i][block_y + j] = imgV_org[(img->pix_c_y + block_y + incr_y*j + off_y)*(img->width_cr) + img->pix_c_x + i] - img->mpr[i][block_y + j];
					}

                }
            }
        }

        //===== DCT, Quantization, inverse Quantization, IDCT, and Reconstruction =====

        if (!skipped&&!img->NoResidueDirect)
        {
            for (j = 0; j < 8; j++){
                for (i = 0; i < 8; i++)
                {
                    tmp_block_88[j*8+i] = img->m7[i][j];
                }
            }
            transform_B8(tmp_block_88, 8);

            scanquant_B8(QP_SCALE_CR[img->qp - MIN_QP], IntraPrediction ? 4 : 0, 4 + uv, 0, tmp_block_88, 0, cr_cbp
#ifdef RDO_Q
                , lambda
#endif
                , 8);

        }
    }

    //===== update currMB->cbp =====
    img->mb_data[img->current_mb_nr].cbp += (*cr_cbp);//((*cr_cbp)<<4); /*lgp*dct*/

}

/*
*************************************************************************
* Function:Predict an intra chroma 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void IntraChromaPrediction8x8 (int *mb_up, int *mb_left, int*mb_up_left)
{
	Macroblock *currMB = &img->mb_data[img->current_mb_nr];
	unsigned char edgepixu[40]= {0};
#define EPU (edgepixu+20)
	unsigned char edgepixv[40]= {0};
#define EPV (edgepixv+20)
	int last_pix,new_pix;
	int bs_x=8;
	int bs_y=8;
	int x, y;

	int     i, j;
	uchar_t *image_org;
	int     block_x, block_y;
	int     img_cx            = img->pix_c_x;
	int     img_cy            = img->pix_c_y;
	int     img_cx_1          = img->pix_c_x-1;
	int     img_cx_4          = img->pix_c_x+4;
	int     img_cy_1          = img->pix_c_y-1;
	int     img_cy_4          = img->pix_c_y+4;
	int     b8_x              = img->pix_c_x/4;
	int     b8_y              = img->pix_c_y/4;
	int     mb_nr             = img->current_mb_nr;
	int     mb_width          = img->width/16;

	/***********************************/
	int	mb_available_up_right=((img_cy==0)||(b8_x>=(img->width_cr/BLOCK_SIZE-2))) ? 0 : (img->mb_data[img->current_mb_nr].slice_nr == img->mb_data[img->current_mb_nr-mb_width+1].slice_nr);
	// int mb_available_left_down;//=((img_cx==0)||(b8_y>=(img->height_cr/BLOCK_SIZE-2))) ? 0 : (img->mb_data[img->current_mb_nr].slice_nr == img->mb_data[img->current_mb_nr+mb_width-1].slice_nr);
	int mb_available_up   = (img_cy == 0) ? 0 : (img->mb_data[img->current_mb_nr].slice_nr == img->mb_data[img->current_mb_nr-mb_width].slice_nr);
	int mb_available_left = (img_cx == 0) ? 0 : (img->mb_data[img->current_mb_nr].slice_nr == img->mb_data[img->current_mb_nr-1].slice_nr);
	int mb_available_up_left = (img_cx/BLOCK_SIZE == 0 || img_cy/BLOCK_SIZE == 0 ) ? 0 : (img->mb_data[img->current_mb_nr].slice_nr == img->mb_data[img->current_mb_nr-mb_width-1].slice_nr);

	int     uv;
	int     mode;
	int     best_mode = DC_PRED_8;         //just an initilaization here, should always be overwritten
	int     cost;
	int     min_cost;
	int     diff[MB_BLOCK_SIZE][MB_BLOCK_SIZE];

	int     incr_y=1,off_y=0;

	unsigned char edgepixu_tmp[40] = { 0 };
	unsigned char edgepixv_tmp[40] = { 0 };
	uchar_t *pedge_U = edgepixu_tmp + 20;
	uchar_t *pedge_V = edgepixv_tmp + 20;
	
	uchar_t* pedge_DC;
	uchar_t* pedge_NDC;

	if (mb_up)
		*mb_up = mb_available_up;
	if (mb_left)
		*mb_left = mb_available_left;
	if( mb_up_left )
		*mb_up_left = mb_available_up_left;

	// compute all chroma intra prediction modes for both U and V
	uv = 0;

	if(mb_available_up)
	{
		for (x = 0; x < bs_x; x++){
			EPU[x + 1] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx + x];
			pedge_U[x + 1] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx + x];
		}

		if(mb_available_up_right){
			for (x = 0; x < bs_y; x++){
				EPU[1 + x + bs_x] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx + bs_x + x];
				pedge_U[1 + x + bs_x] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx + bs_x + x];
			}
		}
		else{
			for (x = 0; x < bs_y; x++)	{
				EPU[1 + x + bs_x] = EPU[bs_x];  //bs_x=8; EPU[9~16]=r[8]  
				pedge_U[1 + x + bs_x] = pedge_U[bs_x];  //bs_x=8; EPU[9~16]=r[8]  
			}
		}
		//by oliver according to 1658
		EPU[0] = imgU[(img_cy - 1)* (img->iStrideC) + img_cx];
		pedge_U[0] = imgU[(img_cy - 1)* (img->iStrideC) + img_cx];
		
	}
	if(mb_available_left)
	{
		for (y = 0; y < bs_y; y++){
			EPU[-1 - y] = imgU[(img_cy + y)*(img->iStrideC) + img_cx - 1];
			pedge_U[-1 - y] = imgU[(img_cy + y)*(img->iStrideC) + img_cx - 1];	
		}

		for (y = 0; y < bs_x; y++){
			EPU[-1 - y - bs_y] = EPU[-bs_y];
			pedge_U[-1 - y - bs_y] = pedge_U[-bs_y];
		}

		EPU[0] = imgU[(img_cy)*(img->iStrideC) + img_cx - 1];
		pedge_U[0] = imgU[(img_cy)*(img->iStrideC) + img_cx - 1];

	}

	if (mb_available_up&&mb_available_left){
		EPU[0] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx - 1];
		pedge_U[0] = imgU[(img_cy - 1)*(img->iStrideC) + img_cx - 1];
	}

	//lowpass (Those emlements that are not needed will not disturb)
	last_pix=EPU[-/*8*/9];     //ITM_r2
	for(i=-8;i<=8;i++)
	{
		new_pix=( last_pix + (EPU[i]<<1) + EPU[i+1] + 2 )>>2;
		last_pix=EPU[i];
		EPU[i]=(unsigned char)new_pix;
	}


	uv = 1;

	if(mb_available_up)
	{
		for (x = 0; x < bs_x; x++){
			EPV[x + 1] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx + x];
			pedge_V[x + 1] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx + x];
		}

		if(mb_available_up_right){
			for (x = 0; x < bs_y; x++){
				EPV[1 + x + bs_x] = imgV[(img_cy - 1)* (img->iStrideC) + img_cx + bs_x + x];
				pedge_V[1 + x + bs_x] = imgV[(img_cy - 1)* (img->iStrideC) + img_cx + bs_x + x];
			}
		}
		else{
			for (x = 0; x < bs_y; x++)	{
				EPV[1 + x + bs_x] = EPV[bs_x];  //bs_x=8; EPV[9~16]=r[8]  
				pedge_V[1 + x + bs_x] = pedge_V[bs_x];  //bs_x=8; EPV[9~16]=r[8]  
			}
		}

		EPV[0] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx];
		pedge_V[0] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx];

	}
	if(mb_available_left)
	{
		for (y = 0; y < bs_y; y++){
			EPV[-1 - y] = imgV[(img_cy + y)*(img->iStrideC) + img_cx - 1];
			pedge_V[-1 - y] = imgV[(img_cy + y)*(img->iStrideC) + img_cx - 1];
		}

		for (y = 0; y < bs_x; y++){
			EPV[-1 - y - bs_y] = EPV[-bs_y];
			pedge_V[-1 - y - bs_y] = pedge_V[-bs_y];
		}

		EPV[0] = imgV[(img_cy)*(img->iStrideC) + img_cx - 1];
		pedge_V[0] = imgV[(img_cy)*(img->iStrideC) + img_cx - 1];

	}


	if (mb_available_up&&mb_available_left){
		EPV[0] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx - 1];
		pedge_V[0] = imgV[(img_cy - 1)*(img->iStrideC) + img_cx - 1];
	}


	//lowpass (Those emlements that are not needed will not disturb)
	last_pix=EPV[-/*8*/9];    //ITM_r2
	for(i=-8;i<=8;i++)
	{
		new_pix=( last_pix + (EPV[i]<<1) + EPV[i+1] + 2 )>>2;
		last_pix=EPV[i];
		EPV[i]=(unsigned char)new_pix;
	}

	// compute all chroma intra prediction modes for both U and V
	for (uv = 0; uv < 2; uv++)
	{
		if (0 == uv)
		{
			pedge_DC = EPU;
			pedge_NDC = pedge_U;
		}
		else
		{
			pedge_DC = EPV;
			pedge_NDC = pedge_V;
		}

		for (block_y = 0; block_y < 8; block_y += 4)
		{
			for (block_x = 0; block_x < 8; block_x += 4)
			{
				intra_pred_chroma(pedge_DC, pedge_NDC, uv, block_x, block_y, mb_available_up, mb_available_left, mb_available_up_left);
			}
		}
		
	}

	if (!input->rdopt) // the rd-opt part does not work correctly (see encode_one_macroblock)
	{                  
		// pick lowest cost prediction mode
		min_cost = 1<<20;
		mode = DC_PRED_8;
		for (mode=DC_PRED_8; mode<=PLANE_8; mode++)
		{
			if ((mode==VERT_PRED_8 && !mb_available_up) ||
				(mode==HOR_PRED_8 && !mb_available_left) ||
				(mode==PLANE_8 && (!mb_available_left || !mb_available_up || !mb_available_up_left)))
				continue;
			cost = 0;
			for (uv=0; uv<2; uv++)
			{
				if (0 == uv)
				{
					image_org = imgU_org;
				}
				else
				{
					image_org = imgV_org;
				}

				for (j = 0; j < 8; j++){
					for (i = 0; i < 8; i++)
					{
						diff[i][j] = image_org[(img_cy + incr_y*j + off_y)*(img->width_cr) + img_cx + i] - img->mprr_c[uv][mode][j * 16 + i + 8];
					}
				}
				cost += find_sad_8x8(input->hadamard,8,8,0,0,diff);
			}

			if (cost < min_cost)
			{
				best_mode = mode;
				min_cost = cost;
			}
		}
		currMB->c_ipred_mode = best_mode;
	}

}


/*
*************************************************************************
* Function: Converts macroblock type to coding value
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int SubMBType2Value (Macroblock* currMB,int layer)
{
	int mbtype;

	if (img->type!=B_IMG)
	{
		if (currMB->mb_type==4)
			currMB->mb_type = P8x8;

		if (currMB->mb_type==I_MB)
			return (img->type==I_IMG ? 0 : 5);

		else if (currMB->mb_type==P8x8)
		{       
			return 4;
		}
		else
			return currMB->mb_type;
	}
	else
	{
		if(currMB->mb_type==4)
			currMB->mb_type = P8x8;

		mbtype = currMB->mb_type;

		if      (mbtype==0)
			return 0;
		else if (mbtype==I_MB)
			return 5;
		else if (mbtype==P8x8)
			return 4;
		else if (mbtype==2)
			return 1 + currMB->b8pdir[2*layer];
		else 
			return 0;

	}
}

/*
*************************************************************************
* Function:Converts 8x8 block tyoe to coding value
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int B8Mode2Value (int b8mode, int b8pdir)
{
	static const int b8start[8] = {0,0,0,0, 1, 4, 5, 10};
	static const int b8inc  [8] = {0,0,0,0, 1, 2, 2, 1};

	if (img->type!=B_IMG)
	{
		if(b8pdir == 0)
			return 0;
		else if(b8pdir == 3)
			return 1;
		else
			return 0;
	}
	else
	{
		return b8start[b8mode] + b8inc[b8mode] * b8pdir;
	}

}

/*
*************************************************************************
* Function: Codes macroblock header
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int writeMBHeader (int rdopt) 
{
	int             i;
	int             mb_nr     = img->current_mb_nr;
	Macroblock*     currMB    = &img->mb_data[mb_nr];
	SyntaxElement  *currSE    = &img->MB_SyntaxElements[currMB->currSEnr];
	int*            bitCount  = currMB->bitcounter;
	int             no_bits   = 0;
	int             mb_x      = img->mb_x;
	int             mb_y      = img->mb_y;
	int			        skip;     
	DataPartition* dataPart;           
	Slice*         currSlice = img->currentSlice ;
	int			       eos_bit;


	skip= currMB->mb_type ? 0:((img->type==B_IMG) ? !currMB->cbp:1);

	currMB->IntraChromaPredModeFlag = IS_INTRA(currMB);

	eos_bit = (img->current_mb_nr != img->currentSlice->start_mb_nr) ? 1 : 0;

    CheckAvailabilityOfNeighborsAEC();

    if (eos_bit && !rdopt) {
        write_terminating_bit (0); 
    }

	if(img->type != I_IMG)//GB
	{
		currSE->type    = SE_MBTYPE;

		dataPart = &(currSlice->partArr[0]);
		currSE->writing=writeMBPartTypeInfo_AEC;
		dataPart->writeSyntaxElement(currSE,dataPart);

#if TRACE
		if (img->type==B_IMG)
			snprintf(currSE->tracestring, TRACESTRING_SIZE, "B_MB mode(%2d,%2d) = %3d",img->mb_x, img->mb_y, currMB->mb_type);
		else
			snprintf(currSE->tracestring, TRACESTRING_SIZE,   "MB mode(%2d,%2d) = %3d",img->mb_x, img->mb_y,currMB->mb_type);
#endif

		bitCount[BITS_MB_MODE] += currSE->len;
		no_bits                += currSE->len;
		currSE++;
		currMB->currSEnr++;
	}

	if (img->type != I_IMG)
	{
		if(img->type!=P_IMG && currMB->mb_type != 0)	// B-frame
		{
			const int iPdirMap[3] = {2, 0, 3}; // FORWORD, BACKWORD, SYM
			if (currMB->mb_type == 1) {		// 1 : B_16x16
				currSE->value1 = iPdirMap[currMB->b8pdir[0]];
				currSE->type   = SE_MBTYPE;

				dataPart = &(currSlice->partArr[0]);
				currSE->writing=write_other_PredTypeInfo_AEC;
				dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
				snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
					i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

				bitCount[BITS_MB_MODE]+= currSE->len;
				no_bits               += currSE->len;
				currSE++;
				currMB->currSEnr++;

			} else if (currMB->mb_type == 2 || currMB->mb_type == 3) {	// 2 : B_16x8, 3 : B_8x16
				int PredMode[2] = { -1, -1 };
				PredMode[0] = iPdirMap[currMB->b8pdir[0]];
				PredMode[1] = iPdirMap[currMB->b8pdir[3]];

				for (i=0; i<2; i++)
				{
					currSE->value1  = PredMode[i];
					currSE->type    = SE_MBTYPE;

					dataPart = &(currSlice->partArr[0]);
					currSE->writing=write_other_PredTypeInfo_AEC;
					dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
						i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

					bitCount[BITS_MB_MODE]+= currSE->len;
					no_bits               += currSE->len;
					currSE++;
					currMB->currSEnr++;
				}

			} else if (currMB->mb_type == P8x8) {	// B_8x8
				for (i=0; i<4; i++)
				{
					currSE->value1  =  currSE->bitpattern = B8Mode2Value (currMB->b8mode[i], currMB->b8pdir[i]);
					currSE->type    = SE_MBTYPE;

					dataPart = &(currSlice->partArr[0]);
					currSE->writing=write_8x8_PredTypeInfo_AEC;
					dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
						i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

					bitCount[BITS_MB_MODE]+= currSE->len;
					no_bits               += currSE->len;
					currSE++;
					currMB->currSEnr++;
				}
			} else {	// B_Intra
			}
		}
		else if(img->type == P_IMG)
		{
			const int skip = 0, fwd = 2, mh = 3;
			if (currMB->mb_type == 0 || currMB->mb_type == 1) {		// 0 : P_Skip, 1 : P_16x16
				if(currMB->mb_type == 0){
					currSE->value1 = 0;
				}
				else{
					if(currMB->b8pdir[0] == 0){ // FORWARD
						currSE->value1 = fwd;
					}
					else if(currMB->b8pdir[0] == 3){ // MHP
						currSE->value1 = mh;
					}
					else{
						printf("Syntax Error! P_16x16_Pred_Type : %d\n", currMB->b8pdir[0]);
						exit(0);
					}
				}
				currSE->type    = SE_MBTYPE;
				dataPart = &(currSlice->partArr[0]);
				currSE->writing=MHMC_write_16x16_PredTypeInfo_AEC;
				dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
				snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
					i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

				bitCount[BITS_MB_MODE]+= currSE->len;
				no_bits               += currSE->len;
				currSE++;
				currMB->currSEnr++;

			} else if (currMB->mb_type == 2 || currMB->mb_type == 3) {		// 2 : P_16x8, 3 : P_8x16
				int PredMode[2] = { -1, -1 };

				if(currMB->b8pdir[0] == 0){ // FORWARD
					PredMode[0] = fwd;
				}
				else if(currMB->b8pdir[0] == 3){ // MHP
					PredMode[0] = mh;
				}
				else{
					printf("Syntax Error! P_16x16_Pred_Type : %d\n", currMB->b8pdir[0]);
					exit(0);
				}

				if(currMB->b8pdir[3] == 0){ // FORWARD
					PredMode[1] = fwd;
				}
				else if(currMB->b8pdir[3] == 3){ // MHP
					PredMode[1] = mh;
				}
				else{
					printf("Syntax Error! P_16x16_Pred_Type : %d\n", currMB->b8pdir[3]);
					exit(0);
				}

				for (i=0; i<2; i++)
				{
					currSE->value1  = PredMode[i];
					currSE->type    = SE_MBTYPE;

					dataPart = &(currSlice->partArr[0]);
					currSE->writing=MHMC_write_other_PredTypeInfo_AEC;
					dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
						i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

					bitCount[BITS_MB_MODE]+= currSE->len;
					no_bits               += currSE->len;
					currSE++;
					currMB->currSEnr++;
				}
			} else if (currMB->mb_type == P8x8) {		// P_8x8
				for (i=0; i<4; i++)
				{
					currSE->value1  =  currSE->bitpattern = B8Mode2Value (currMB->b8mode[i], currMB->b8pdir[i]);
					currSE->type    = SE_MBTYPE;

					dataPart = &(currSlice->partArr[0]);
					currSE->writing=MHMC_write_other_PredTypeInfo_AEC;
					dataPart->writeSyntaxElement(currSE,dataPart);
#if TRACE
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "8x8 mode/pdir(%2d) = %3d/%d",
						i,currMB->b8mode[i],currMB->b8pdir[i]);
#endif

					bitCount[BITS_MB_MODE]+= currSE->len;
					no_bits               += currSE->len;
					currSE++;
					currMB->currSEnr++;
				}
			} else {	// P_Intra
			}
		}
	}

	if (IS_INTRA(currMB) && input->abt_enable) {
        currSE->value1 = currMB->trans_type;
        currSE->type = SE_TUTYPE;
		dataPart = &(currSlice->partArr[0]);
		currSE->writing = writeMBTransType_AEC;
		dataPart->writeSyntaxElement(currSE,dataPart);

        bitCount[BITS_MB_MODE] += currSE->len;
        no_bits                += currSE->len;
#if TRACE
        snprintf(currSE->tracestring, TRACESTRING_SIZE, "transform type: %d", currMB->trans_type);
#endif
        currSE++;
        currMB->currSEnr++;
    }

    if(img->type == P_IMG && input->number_reference_frame > 1 && img->number > 1) 
    {
        if( IS_P8x8 (currMB) )
        {
            for (i=0; i<4; i++)
            {
				currSE->value1 = ref_idx[currMB->fw_ref[i]];
				if (currSE->value1 < 0) {
					printf("Reference Frame Index Error!\n");
					exit(0);
				}

                currSE->type    = SE_MBTYPE;
                currSE->value2  = 0;

				dataPart = &(currSlice->partArr[0]);
				currSE->writing=write_Reffrm_AEC;
				dataPart->writeSyntaxElement(currSE,dataPart);

				refbits[ref_idx[currMB->fw_ref[i]]] = currSE->len;
               
                bitCount[BITS_MB_MODE]+= currSE->len;
                no_bits               += currSE->len;
                currSE++;
                currMB->currSEnr++;
            }
        }else if(currMB->mb_type == 1) {
			currSE->value1 = ref_idx[currMB->fw_ref[0]];
			if (currSE->value1 < 0) {
				printf("Reference Frame Index Error!\n");
				exit(0);
			}          
            currSE->type    = SE_MBTYPE;            
            currSE->value2  = 0;

			dataPart = &(currSlice->partArr[0]);
			currSE->writing=write_Reffrm_AEC;
			dataPart->writeSyntaxElement(currSE,dataPart);
            refbits[ref_idx[currMB->fw_ref[0]]] = currSE->len;

            bitCount[BITS_MB_MODE]+= currSE->len;
            no_bits               += currSE->len;
            currSE++;
            currMB->currSEnr++;
        }
        else if(currMB->mb_type == 2 || currMB->mb_type == 3)  {
            for (i=0; i<2; i++)
            {
				if(currMB->mb_type == 2) {
					currSE->value1 = ref_idx[currMB->fw_ref[i*2]];
				} else {
					currSE->value1 = ref_idx[currMB->fw_ref[i]];
				}
				if (currSE->value1 < 0) {
					printf("Reference Frame Index Error!\n");
					exit(0);
				}

                currSE->type    = SE_MBTYPE;
                currSE->value2  = 0;
                
				dataPart = &(currSlice->partArr[0]);
				currSE->writing=write_Reffrm_AEC;
				dataPart->writeSyntaxElement(currSE,dataPart);

				if(currMB->mb_type == 2) {
					refbits[ref_idx[currMB->fw_ref[i*2]]] = currSE->len;
				} else {
					refbits[ref_idx[currMB->fw_ref[i]]] = currSE->len;
				}

                bitCount[BITS_MB_MODE]+= currSE->len;
                no_bits               += currSE->len;
                currSE++;
                currMB->currSEnr++;
            }
        }
    }

	if(IS_INTRA(currMB)) {
        if (currMB->trans_type != TRANS_2Nx2N) {
            int b8, b4;
            for (b8 = 0; b8 < 4; b8++) {
                currSE->context = b8;
                currSE->value1 = currMB->trans_split[b8];
                currSE->type = SE_INTRAPREDMODE;
                dataPart = &(currSlice->partArr[0]);
                currSE->writing = writeIntraSplit_AEC;
                dataPart->writeSyntaxElement(currSE, dataPart);
                bitCount[BITS_MB_MODE] += currSE->len;
                no_bits += currSE->len;
                currSE++;
                currMB->currSEnr++;
            }
            for (b8 = 0; b8 < 4; b8++) {
                int cnt = currMB->trans_split[b8] == 0 ? 1 : 4;
                for (b4 = 0; b4 < cnt; b4++) {
                    currSE->context = b8;//need modification???
                    currSE->value1 = currMB->intra_pred_modes[b8 * 4 + b4];
#if TRACE
                    snprintf(currSE->tracestring, TRACESTRING_SIZE, "Intra mode     = %3d %d", currSE->value1, currSE->context);
#endif
                    currSE->type = SE_INTRAPREDMODE;
                    dataPart = &(currSlice->partArr[0]);
                    currSE->writing = writeIntraPredMode_AEC;
                    dataPart->writeSyntaxElement(currSE, dataPart);
                    bitCount[BITS_MB_MODE] += currSE->len;
                    no_bits += currSE->len;
                    currSE++;
                    currMB->currSEnr++;
                }
            }
        } else { 
            currSE->context = 0;//need modification???
            currSE->value1 = currMB->intra_pred_modes[0];

#if TRACE
            snprintf(currSE->tracestring, TRACESTRING_SIZE, "Intra mode     = %3d %d",currSE->value1,currSE->context);
#endif

            /*--- set symbol type and function pointers ---*/
            currSE->type = SE_INTRAPREDMODE;

			dataPart = &(currSlice->partArr[0]);
			currSE->writing = writeIntraPredMode_AEC;
			dataPart->writeSyntaxElement(currSE, dataPart);
            bitCount[BITS_MB_MODE] += currSE->len;
            no_bits += currSE->len;
            currSE++;
            currMB->currSEnr++;
        }
    }
	if(IS_INTRA(currMB))
	{
		currSE->value1 = currMB->c_ipred_mode;
		dataPart = &(currSlice->partArr[0]);
		currSE->writing=writeCIPredMode_AEC;
		dataPart->writeSyntaxElement(currSE,dataPart);
		bitCount[BITS_MB_MODE] += currSE->len;
		no_bits                    += currSE->len;
#if TRACE
		snprintf(currSE->tracestring, TRACESTRING_SIZE, "Chroma intra pred mode %d", currMB->c_ipred_mode);
#endif
		currSE++;
		currMB->currSEnr++;
	}
	return no_bits;
}

/*
*************************************************************************
* Function:Sets context for reference frame parameter
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int BType2CtxRef (int btype)
{
	if (btype<4)   return 0;
	else           return 1;
}

/*
*************************************************************************
* Function:Writes motion vectors of an 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int writeMotionVector8x8 (int  i0,
	int  j0,
	int  i1,
	int  j1,
	int  refframe,
	int  dmv_flag,
	int  fwd_flag,
	int  mv_mode)
{
	int            i, j, k, l, m;
	int            curr_mvd;
	int            bwflag      = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate        = 0;
	int            step_h      = input->blc_size[mv_mode][0] >> 3;
	int            step_v      = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB      = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE      = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount    = currMB->bitcounter;
	int            refindex    = (refframe<0 ? 0 : refframe);
	int*****       all_mv      = (fwd_flag ? img->all_mv : img->all_bmv);
	int*****       pred_mv     = ((img->type!=B_IMG) ? img->mv : (fwd_flag ? img->p_fwMV : img->p_bwMV));
	Slice*         currSlice  = img->currentSlice;
	DataPartition* dataPart;
	if (!fwd_flag) bwflag = 1;

	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{
			for (k=0; k<2; k++) 
			{
				curr_mvd = all_mv[i][j][refindex][mv_mode][k] - pred_mv[i][j][refindex][mv_mode][k];

				//--- store (oversampled) mvd ---
				for (l=0; l < step_v; l++) 
					for (m=0; m < step_h; m++)    currMB->mvd[bwflag][j+l][i+m][k] = curr_mvd;

				currSE->value1 = curr_mvd;
				currSE->type   = ((img->type==B_IMG) ? SE_BFRAME : SE_MVD);

				img->subblock_x = i; // position used for context determination
				img->subblock_y = j; // position used for context determination
				currSE->value2  = 2*k+fwd_flag; // identifies the component and the direction; only used for context determination
				currSE->writing = writeMVD_AEC;
				dataPart = &(currSlice->partArr[0]);
				dataPart->writeSyntaxElement (currSE, dataPart);

#if TRACE
				{
					if (fwd_flag)
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "FMVD(%d) = %3d  (org_mv %3d pred_mv %3d) %d",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k],currSE->value2);
					}
					else
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "BMVD(%d) = %3d  (org_mv %3d pred_mv %3d)",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k]);
					}
				}
#endif

				bitCount[BITS_INTER_MB] += currSE->len;
				rate                    += currSE->len;
				currSE++;  
				currMB->currSEnr++;
			}
		}

		return rate;
}

int MHMC_writeMotionVector8x8 (int  i0,
							   int  j0,
							   int  i1,
							   int  j1,
							   int  refframe,
							   int  dmv_flag,
							   int  fwd_flag,
							   int  mv_mode)
{
	int            i, j, k, l, m;
	int            curr_mvd;
	int            bwflag      = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate        = 0;
	int            step_h      = input->blc_size[mv_mode][0] >> 3;
	int            step_v      = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB      = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE      = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount    = currMB->bitcounter;
	int            refindex    = (refframe<0 ? 0 : refframe);
	int*****       all_mv      = img->all_Lbimv;
	int*****       pred_mv     = img->Lbimv;
	Slice*         currSlice  = img->currentSlice;
	DataPartition* dataPart;
	if (!fwd_flag) bwflag = 0;

	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{
			for (k=0; k<2; k++) 
			{
				curr_mvd = all_mv[i][j][refindex][mv_mode][k] - pred_mv[i][j][refindex][mv_mode][k];

				//--- store (oversampled) mvd ---
				for (l=0; l < step_v; l++) 
					for (m=0; m < step_h; m++)    currMB->mvd[bwflag][j+l][i+m][k] = curr_mvd;

				currSE->value1 = curr_mvd;
				currSE->type   = ((img->type==B_IMG) ? SE_BFRAME : SE_MVD);

				img->subblock_x = i; // position used for context determination
				img->subblock_y = j; // position used for context determination
				currSE->value2  = 2*k+bwflag; // identifies the component and the direction; only used for context determination
				currSE->writing = writeMVD_AEC;
				dataPart = &(currSlice->partArr[0]);
				dataPart->writeSyntaxElement (currSE, dataPart);

#if TRACE
				{
					if (fwd_flag)
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "FMVD(%d) = %3d  (org_mv %3d pred_mv %3d) %d",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k],currSE->value2);
					}
					else
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "BMVD(%d) = %3d  (org_mv %3d pred_mv %3d)",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k]);
					}
				}
#endif
				mvbits[curr_mvd] = currSE->len;

				bitCount[BITS_INTER_MB] += currSE->len;
				rate                    += currSE->len;
				currSE++;  
				currMB->currSEnr++;
			}
		}

		return rate;
}

/*
*************************************************************************
* Function:Writes motion vectors of an 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int
	writeMotionVector8x8_bid (int  i0,
	int  j0,
	int  i1,
	int  j1,
	int  refframe,
	int  dmv_flag,
	int  fwd_flag,
	int  mv_mode,
	int  pdir)
{
	int            i, j, k, l, m;
	int            curr_mvd;
	int            bwflag     = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate       = 0;
	int            step_h     = input->blc_size[mv_mode][0] >> 3;
	int            step_v     = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB     = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE     = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount   = currMB->bitcounter;
	int            refindex   = (refframe<0 ? 0 : refframe);
	int*****       all_mv     = (fwd_flag ? img->all_mv : img->all_bmv);
	int*****       pred_mv    = ((img->type!=B_IMG) ? img->mv : (fwd_flag ? img->p_fwMV : img->p_bwMV));
	Slice*         currSlice  = img->currentSlice;
	DataPartition* dataPart;
	if (!fwd_flag) bwflag = 1;

	if(pdir == 2 && mv_mode != 0)
	{
		//sw 10.1
		all_mv = img->all_omv;
		pred_mv = img->omv;
	}

	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{

			for (k=0; k<2; k++) 
			{

				curr_mvd = all_mv[i][j][refindex][mv_mode][k] - pred_mv[i][j][refindex][mv_mode][k];

				//--- store (oversampled) mvd ---
				for (l=0; l < step_v; l++) 
					for (m=0; m < step_h; m++)    currMB->mvd[bwflag][j+l][i+m][k] = curr_mvd;

				currSE->value1 = curr_mvd;
				currSE->type   = (img->type==B_IMG ? SE_BFRAME : SE_MVD);

				img->subblock_x = i; // position used for context determination
				img->subblock_y = j; // position used for context determination
				currSE->value2  = 2*k+(1-fwd_flag); // identifies the component and the direction; only used for context determination
				currSE->writing = writeMVD_AEC;
				dataPart = &(currSlice->partArr[0]);
				dataPart->writeSyntaxElement (currSE, dataPart);
#if TRACE
				if (fwd_flag)
				{
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "FMVD(%d) = %3d  (org_mv %3d pred_mv %3d) %d",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k],currSE->value2);
				}
				else
				{
					snprintf(currSE->tracestring, TRACESTRING_SIZE, "BMVD(%d) = %3d  (org_mv %3d pred_mv %3d)",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k]);
				}
#endif
				mvbits[curr_mvd] = currSE->len;

				bitCount[BITS_INTER_MB] += currSE->len;
				rate                    += currSE->len;
				currSE++;  
				currMB->currSEnr++;
			}
		}

		return rate;
}
/*<!***************EDIT start by lzhang***********************/
int writeLumaCoeff8x8_AEC (int b8, int b4, int intra_mode, int bsize)
{
	int             rate      = 0;
	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	SyntaxElement*  currSE    = &img->MB_SyntaxElements[currMB->currSEnr];
	Slice*          currSlice = img->currentSlice;
	int*            bitCount  = currMB->bitcounter;
	DataPartition*  dataPart;

    int coef_num = bsize * bsize;
	int level, run;
	int   k;
    int*  ACLevel = img->cofAC[b8][b4][0];
    int*  ACRun = img->cofAC[b8][b4][1];

	//added 1.6    
	level = 1; // get inside loop
    DCT_Block_Size = bsize;

    for (k = 0; k <= coef_num && level != 0; k++) {
        level = currSE->value1 = ACLevel[k]; // level
        run = currSE->value2 = ACRun[k]; // run
        currSE->writing = writeRunLevel_AEC_Ref;
        currSE->context = LUMA_8x8;
        currSE->type = ((intra_mode ? SE_LUM_AC_INTRA : SE_LUM_AC_INTER));
        dataPart = &(currSlice->partArr[0]);
        dataPart->writeSyntaxElement(currSE, dataPart);
        bitCount[BITS_COEFF_Y_MB] += currSE->len;
        rate += currSE->len;
#if TRACE
        snprintf(currSE->tracestring, TRACESTRING_SIZE, "Luma8x8 sng(%2d) level =%3d run =%2d", k, level, run);
#endif
        /* proceed to next SE */
        currSE++;
        currMB->currSEnr++;
    }
    return rate;
}

int writeChromaCoeff8x8_AEC (int b8 )
{
	int             rate      = 0;
	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	SyntaxElement*  currSE    = &img->MB_SyntaxElements[currMB->currSEnr];
	int*            bitCount  = currMB->bitcounter;
	Slice*          currSlice = img->currentSlice;
	int             cbp       = currMB->cbp;
	DataPartition*  dataPart;
	int			  level, run, ipos=-1;
	int			  k;
    int*			ACLevel = img->cofAC[b8][0][0];
    int*            ACRun = img->cofAC[b8][0][1];
	int			  vlc_numcoef = 0;
	int             b8_ctr;
	//added by lzhang for AEC
	img->subblock_y = 0;
	img->subblock_x = 0;
	b8_ctr = b8;       //added 1.6
    DCT_Block_Size = 8;
	if( (cbp>>(4*b8)) & 0x01 )
	{
		level = 1; // get inside loop
		for( k=0; k<65 && level!=0; k++ )
		{
			level = currSE->value1 = ACLevel[k]; // level
			run   = currSE->value2 = ACRun  [k]; // run
			currSE->writing = writeRunLevel_AEC_Ref;
			currSE->context     =  CHROMA_AC;
			img->is_intra_block =  IS_INTRA(currMB);
			img->is_v_block     =  (b8>4) ? 1:0 ;
			currSE->type        = (IS_INTRA(currMB) ? SE_CHR_AC_INTRA : SE_CHR_AC_INTER);
			// choose the appropriate data partition
			dataPart = &(currSlice->partArr[0]); 
			dataPart->writeSyntaxElement (currSE, dataPart);
			bitCount[BITS_COEFF_UV_MB] += currSE->len;
			rate                       += currSE->len;
#if TRACE
			snprintf(currSE->tracestring, TRACESTRING_SIZE, "AC Chroma8x8 %2d: level =%3d run =%2d",k, level, run);
#endif
			// proceed to next SE 
			currSE++;  
			currMB->currSEnr++;
		}
	}
	return rate;
}
/*<!***************EDIT END by lzhang***********************/
/*
*************************************************************************
* Function:Writes Luma Coeff of an 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int writeLumaCoeff8x8 (int b8, int b4, int intra8x8mode)
{
	int  rate = 0;
    int bsize = 8;
	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	SyntaxElement*  currSE    = &img->MB_SyntaxElements[currMB->currSEnr];

    if (currMB->trans_type == TRANS_2Nx2N) {
        bsize = 16;
    } else if (currMB->trans_split[b8]) {
        bsize = 4;
    }

	if((img->type!=I_IMG)&&(IS_INTRA(currMB)))
		img->is_intra_block = 1;
	else
		img->is_intra_block = intra8x8mode;
	rate  += writeLumaCoeff8x8_AEC(b8, b4, intra8x8mode, bsize);

	return rate;
}

/*
*************************************************************************
* Function:Writes CBP, DQUANT, and Luma Coefficients of an macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int
	StoreMotionVector8x8 (int  i0,
	int  j0,
	int  i1,
	int  j1,
	int  refframe,
	int  dmv_flag,
	int  fwd_flag,
	int  mv_mode)
{
	int            i, j, k, l, m;
	int            curr_mvd;
	int            bwflag     = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate       = 0;
	int            step_h     = input->blc_size[mv_mode][0] >> 3;
	int            step_v     = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB     = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE     = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount   = currMB->bitcounter;

	int            refindex   = (refframe<0 ? 0 : refframe);
	int*****       all_mv     = (fwd_flag ? img->all_mv : img->all_bmv);
	int*****       pred_mv    = ((img->type!=B_IMG) ? img->mv : (fwd_flag ? img->p_fwMV : img->p_bwMV));

	if (!fwd_flag) bwflag = 1;

	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{
			for (k=0; k<2; k++) 
			{
				curr_mvd = all_mv[i][j][refindex][mv_mode][k] - pred_mv[i][j][refindex][mv_mode][k];

				//--- store (oversampled) mvd ---
				for (l=0; l < step_v; l++) 
					for (m=0; m < step_h; m++)    currMB->mvd[bwflag][j+l][i+m][k] = curr_mvd;
			}
		}

		return 0;
}
/*<!!!!**********ENDIT START by lzhang********************/
int writeChromaCoeff8x8 (int block8x8,int intramode)
{
	int  rate = 0;
	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	SyntaxElement*  currSE    = &img->MB_SyntaxElements[currMB->currSEnr];
	rate += writeChromaCoeff8x8_AEC(block8x8);

	return rate;
}
/*<!!!!**********ENDIT end by lzhang********************/

int
	StoreMotionVector8x8_bid (int  i0,
	int  j0,
	int  i1,
	int  j1,
	int  refframe,
	int  dmv_flag,
	int  fwd_flag,
	int  mv_mode,
	int  pdir)
{
	int            i, j, k, l, m;
	int            curr_mvd;
	int            bwflag     = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate       = 0;
	int            step_h     = input->blc_size[mv_mode][0] >> 3;
	int            step_v     = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB     = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE     = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount   = currMB->bitcounter;

	int            refindex   = (refframe<0 ? 0 : refframe);
	int*****       all_mv     = (fwd_flag ? img->all_mv : img->all_bmv);
	int*****       pred_mv    = ((img->type!=B_IMG) ? img->mv : (fwd_flag ? img->p_fwMV : img->p_bwMV));
	if (!fwd_flag) bwflag = 1;

	if(pdir == 2 && mv_mode != 0)
	{
		all_mv = img->all_omv;
		pred_mv = img->omv;
	}

	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{
			for (k=0; k<2; k++) 
			{
				curr_mvd = all_mv[i][j][refindex][mv_mode][k] - pred_mv[i][j][refindex][mv_mode][k];

				//--- store (oversampled) mvd ---
				for (l=0; l < step_v; l++) 
					for (m=0; m < step_h; m++) 
						currMB->mvd[bwflag][j+l][i+m][k] = curr_mvd;
			}
		}

		return 0;
}

/*
*************************************************************************
* Function:Writes motion vectors of an 8x8 block
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/


int
	writeMVD8x8 (int  i0,
	int  j0,
	int  i1,
	int  j1,
	int  refframe,
	int  dmv_flag,
	int  fwd_flag,
	int  mv_mode)
{
	int            i, j, k;
	int            curr_mvd;
	int            bwflag     = ((refframe<0 || (!fwd_flag))?1:0);
	int            rate       = 0;
	int            step_h     = input->blc_size[mv_mode][0] >> 3;
	int            step_v     = input->blc_size[mv_mode][1] >> 3;
	Macroblock*    currMB     = &img->mb_data[img->current_mb_nr];
	SyntaxElement* currSE     = &img->MB_SyntaxElements[currMB->currSEnr];
	int*           bitCount   = currMB->bitcounter;

	int            refindex   = (refframe<0 ? 0 : refframe);
	int*****       all_mv     = (fwd_flag ? img->all_mv : img->all_bmv);
	int*****       pred_mv    = ((img->type!=B_IMG) ? img->mv : (fwd_flag ? img->p_fwMV : img->p_bwMV));
	//!<added by lzhang for AEC
	Slice*         currSlice  = img->currentSlice;
	DataPartition* dataPart;

	if (!fwd_flag) 
		bwflag = 1;


	for (j=j0; j<j1; j+=step_v)
		for (i=i0; i<i1; i+=step_h)
		{
			for (k=0; k<2; k++) 
			{
				curr_mvd = currMB->mvd[bwflag][j][i][k];

				currSE->value1 = curr_mvd;
				currSE->type   = ((img->type==B_IMG) ? SE_BFRAME : SE_MVD);
				img->subblock_x = i; // position used for context determination
				img->subblock_y = j; // position used for context determination
				currSE->value2  = 2*k+bwflag; // identifies the component and the direction; only used for context determination
				currSE->writing = writeMVD_AEC;
				dataPart = &(currSlice->partArr[0]);
				dataPart->writeSyntaxElement (currSE, dataPart); 
#if TRACE
				{
					if (fwd_flag)
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "FMVD(%d) = %3d  (org_mv %3d pred_mv %3d) %d",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k],currSE->value2);
					}
					else
					{
						snprintf(currSE->tracestring, TRACESTRING_SIZE, "BMVD(%d) = %3d  (org_mv %3d pred_mv %3d)",k, curr_mvd, all_mv[i][j][refindex][mv_mode][k], pred_mv[i][j][refindex][mv_mode][k]);
					}
				}
#endif
				mvbits[curr_mvd] = currSE->len;

				bitCount[BITS_INTER_MB] += currSE->len;
				rate                    += currSE->len;
				currSE++;  
				currMB->currSEnr++;
			}
		}

		return rate;
}

int writeCBPandDqp(int pos, int *rate_top, int *rate_bot)
{
    int             rate = 0;
    Macroblock*     currMB = &img->mb_data[img->current_mb_nr];
    int*            bitCount = currMB->bitcounter;
    SyntaxElement*  currSE = &img->MB_SyntaxElements[currMB->currSEnr];
    DataPartition*  dataPart;
    Slice*          currSlice = img->currentSlice;

    //=====   C B P   =====
    currSE->value1 = currMB->cbp; //CBP
    currSE->writing = writeCBP_AEC;
    dataPart = &(currSlice->partArr[0]);
    dataPart->writeSyntaxElement(currSE, dataPart);
    bitCount[BITS_CBP_MB] += currSE->len;
    rate = currSE->len;
#if TRACE
    snprintf(currSE->tracestring, TRACESTRING_SIZE, "CBP (%2d,%2d) = %3d", img->mb_x, img->mb_y, currMB->cbp);
#endif
    currSE++;
    currMB->currSEnr++;


    *rate_top += rate / 2;
    *rate_bot += rate / 2;

    return 0;

}



/*
*************************************************************************
* Function:Writes motion info
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int storeMotionInfo (int pos)
{
	int k, j0, i0, refframe;

	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	int             no_bits   = 0;

	int   bframe          = (img->type==B_IMG);
	int** refframe_array  = ((img->type==B_IMG) ? fw_refFrArr : refFrArr);
	int** bw_refframe_array  = bw_refFrArr;
	int   multframe       = (input->no_multpred>1); 
	int   step_h0         = (input->blc_size[(IS_P8x8(currMB))? 4 : currMB->mb_type][0] >> 3);
	int   step_v0         = (input->blc_size[(IS_P8x8(currMB))? 4 : currMB->mb_type][1] >> 3);
	int   b8_y     = img->block8_y;
	int   b8_x     = img->block8_x;

	//===== write forward motion vectors =====
	if (IS_INTERMV (currMB))
	{
		for (j0=pos; j0<2; j0+=step_v0)
			for (i0=0; i0<2; i0+=step_h0)
			{
				k=j0*2+i0;
				if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)//has forward vector
				{
					refframe  = refframe_array[b8_y+j0][b8_x+i0];

					if(currMB->b8pdir[k]==2)	{	
						StoreMotionVector8x8_bid(i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 1, currMB->b8mode[k],currMB->b8pdir[k]);		    }
					else
						StoreMotionVector8x8(i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 1, currMB->b8mode[k]);
				}
			}
	}

	//===== write backward motion vectors =====
	if (IS_INTERMV (currMB) && bframe)
	{
		for (j0=pos; j0<2; j0+=step_v0)
			for (i0=0; i0<2; i0+=step_h0)
			{
				k=j0*2+i0;
				if ((currMB->b8pdir[k]==1 || currMB->b8pdir[k]==2) && currMB->b8mode[k]!=0)//has backward vector
				{
					refframe  = bw_refframe_array[b8_y+j0][b8_x+i0];
					StoreMotionVector8x8(i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 0, currMB->b8mode[k]);
				}
			}
	}
	return no_bits;
}

/*
*************************************************************************
* Function:
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

int writeMVD (int pos,int *rate_top,int *rate_bot)
{
	int k, j0, i0, refframe;

	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	int             no_bits   = 0;

	int   bframe          = (img->type==B_IMG);
	int** refframe_array  = ((img->type==B_IMG) ? fw_refFrArr : refFrArr);
	int** bw_refframe_array  = bw_refFrArr;
	int   multframe       = (input->no_multpred>1); 
	int   step_h0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][0] >> 3);
	int   step_v0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][1] >> 3);
	int   b8_y     = img->block8_y;
	int   b8_x     = img->block8_x;

	if(currMB->mb_type!=I_MB)
	{				
		step_h0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][0] >> 3);
		step_v0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][1] >> 3);
	}

	for (j0=pos; j0<2; )
	{ 
		if((currMB->mb_type==I_MB&&j0==0)) { j0 += 1; continue;}

		for (i0=0; i0<2; )
		{
			k=j0*2+i0;

			no_bits = 0;
			if ((currMB->b8pdir[k]==0 || currMB->b8pdir[k]==2 || currMB->b8pdir[k]==3) && currMB->b8mode[k]!=0)//has forward vector
			{
				refframe  = refframe_array[b8_y+j0][b8_x+i0];
				if(currMB->b8pdir[k]==2)
				{	
					no_bits  += writeMotionVector8x8_bid (i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 1, currMB->b8mode[k],currMB->b8pdir[k]);			
				}
				else if(currMB->b8pdir[k]==3)
				{
					no_bits += MHMC_writeMotionVector8x8(i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 1, currMB->b8mode[k]);
				}
				else 
					no_bits   = writeMVD8x8 (i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 1, currMB->b8mode[k]);
			}

			if(j0<1)
				*rate_top += no_bits;
			else
				*rate_bot += no_bits;

			i0+=max(1,step_h0);
		}
		j0+=max(1,step_v0);

	}

	if (bframe)
	{
		for (j0=pos; j0<2; )
		{
			if((currMB->mb_type==I_MB&&j0==0)) { j0 += 1; continue;}

			for (i0=0; i0<2; )
			{
				k=j0*2+i0;

				no_bits = 0;

				if ((currMB->b8pdir[k]==1) && currMB->b8mode[k]!=0)//has backward vector
				{
					refframe  = bw_refframe_array[b8_y+j0][b8_x+i0];
					no_bits   = writeMVD8x8 (i0, j0, i0+step_h0, j0+step_v0, refframe, 0, 0, currMB->b8mode[k]);					  
				}

				if(j0<1)
					*rate_top += no_bits;
				else
					*rate_bot += no_bits;

				i0+=max(1,step_h0);
			}
			j0+=max(1,step_v0); 
		}
	}

	return 0;
}

/*
*************************************************************************
* Function:Writes CBP, DQUANT, and Luma Coefficients of an macroblock
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/
int writeBlockCoeff (int block8x8)
{
	int             rate      = 0;
	Macroblock*     currMB    = &img->mb_data[img->current_mb_nr];
	int*            bitCount  = currMB->bitcounter;
	SyntaxElement*  currSE    = &img->MB_SyntaxElements[currMB->currSEnr];

    if (block8x8 < 4 && block8x8 != 0 && currMB->trans_type == TRANS_2Nx2N) {
        return 0;
    }

    assert(block8x8 < 6);

    if (block8x8 < 4 && currMB->trans_split[block8x8] && currMB->trans_type == TRANS_NxN) {
        int b4;
        for (b4 = 0; b4 < 4; b4++){
            if (currMB->cbp & (1 << (block8x8 * 4 + b4))) {
                rate += writeLumaCoeff8x8(block8x8, b4, (currMB->b8mode[block8x8] == IBLOCK));
            }
        }
    } else {
        if (currMB->cbp & (0xF << (block8x8 * 4))) {
            if (block8x8 < 4) {
                rate += writeLumaCoeff8x8(block8x8, 0, (currMB->b8mode[block8x8] == IBLOCK));
            } else {
                rate += writeChromaCoeff8x8(block8x8, IS_INTRA(currMB));
            }
        }
    }

	return rate;
}


/*
*************************************************************************
* Function:Passes the chosen syntax elements to the NAL
* Input:
* Output:
* Return: 
* Attention:
*************************************************************************
*/

void write_one_macroblock (int eos_bit)
{
	Macroblock* currMB   = &img->mb_data[img->current_mb_nr];
	int*        bitCount = currMB->bitcounter;
	int i;
	int mb_x = img->mb_x;
	int mb_y = img->mb_y;
	int dummy;
	extern int AEC_encoding;               
	Slice *currSlice = img->currentSlice ;
	AEC_encoding = 1;                     

	//--- write header ---
	writeMBHeader (0);

	//  Do nothing more if copy and inter mode
	if ((IS_INTERMV (currMB)  || IS_INTRA (currMB)  ) || ((img->type==B_IMG)     && currMB->cbp != 0)  ) { 
        if (img->type == B_IMG && !IS_INTRA(currMB)) {
            GetBidMVD();
        }
		writeMVD(0,&dummy,&dummy);
		writeCBPandDqp(0,&dummy,&dummy);
        for (i = 0; i < 6; i++) {
            writeBlockCoeff(i);
        }
	}

	//--- set total bit-counter ---
	bitCount[BITS_TOTAL_MB] = bitCount[BITS_MB_MODE] + bitCount[BITS_COEFF_Y_MB]     + bitCount[BITS_INTER_MB]
	+ bitCount[BITS_CBP_MB]  + bitCount[BITS_DELTA_QUANT_MB] + bitCount[BITS_COEFF_UV_MB];
	stat->bit_slice += bitCount[BITS_TOTAL_MB];
}
/*!
************************************************************************
* \brief
*    returns the x and y sample coordinates for a given MbAddress
* \author: added by lzhang
************************************************************************
*/
void get_mb_pos (int mb_addr, int *x, int*y)
{
	//int  PicWidthInMbs = input->img_width/MB_BLOCK_SIZE;
	int  PicWidthInMbs = img->width/MB_BLOCK_SIZE;
	*x = (mb_addr % PicWidthInMbs);
	*y = (mb_addr / PicWidthInMbs);
	(*x) *= MB_BLOCK_SIZE;
	(*y) *= MB_BLOCK_SIZE;
}
/*!
************************************************************************
* \brief
*    get neighbouring positions for non-aff coding
* \param curr_mb_nr
*   current macroblock number (decoding order)
* \param xN
*    input x position
* \param yN
*    input y position
* \param luma
*    1 if luma coding, 0 for chroma
* \param pix
*    returns position informations
* \author: added by lzhang
************************************************************************
*/
void getNeighbour(int curr_mb_nr, int xN, int yN, int luma, PixelPos *pix)
{
	Macroblock *currMb = &img->mb_data[curr_mb_nr];
	int maxWH;

	if (luma)
		maxWH = 16;
	else
		maxWH = 8;

	if ((xN<0)&&(yN<0))
	{
		pix->mb_addr   = currMb->mbAddrD;
		pix->available = currMb->mbAvailD;
	}
	else
		if ((xN<0)&&((yN>=0)&&(yN<maxWH)))
		{
			pix->mb_addr  = currMb->mbAddrA;
			pix->available = currMb->mbAvailA;
		}
		else
			if (((xN>=0)&&(xN<maxWH))&&(yN<0))
			{
				pix->mb_addr  = currMb->mbAddrB;
				pix->available = currMb->mbAvailB;
			}
			else
				if (((xN>=0)&&(xN<maxWH))&&((yN>=0)&&(yN<maxWH)))
				{
					pix->mb_addr  = curr_mb_nr;
					pix->available = 1;
				}
				else
					if ((xN>=maxWH)&&(yN<0))
					{
						pix->mb_addr  = currMb->mbAddrC;
						pix->available = currMb->mbAvailC;
					}
					else 
					{
						pix->available = 0;
					}
					//if (pix->available || img->DeblockCall)
					if(pix->available)
					{
						pix->x = (xN + maxWH) % maxWH;
						pix->y = (yN + maxWH) % maxWH;
						get_mb_pos(pix->mb_addr, &(pix->pos_x), &(pix->pos_y));
						if (luma)
						{
							pix->pos_x += pix->x;
							pix->pos_y += pix->y;
						}
						else
						{
							pix->pos_x = (pix->pos_x/2) + pix->x;
							pix->pos_y = (pix->pos_y/2) + pix->y;
						}
					}
}
/*!
************************************************************************
* \brief
*    get neighbouring  get neighbouring 8x8 luma block
* \param curr_mb_nr
*   current macroblock number (decoding order)
* \param block_x
*    input x block position
* \param block_y
*    input y block position
* \param rel_x
*    relative x position of neighbor
* \param rel_y
*    relative y position of neighbor
* \param pix
*    returns position informations
************************************************************************
*/

void getLuma8x8Neighbour (int curr_mb_nr, int b8_x, int b8_y, int rel_x, int rel_y, PixelPos *pix)
{
	int x = 8* b8_x + rel_x;
	int y = 8* b8_y + rel_y;

	int b8, b8_dest;   
	int pdir, pdir_dest;

	getNeighbour(curr_mb_nr, x, y, 1, pix);


	if (pix->available)
	{

		b8=b8_x+b8_y*2;
		b8_dest=pix->x/8+pix->y/8*2;
		pdir=img->mb_data[curr_mb_nr].b8pdir[b8];
		pdir_dest=img->mb_data[pix->mb_addr].b8pdir[b8_dest];
		if((pdir==0 && pdir_dest==1) || (pdir==1 && pdir_dest==0) || (pdir==2 && pdir_dest==1)||(pdir==1 && pdir_dest==2))
			pix->available=0;
		//

		pix->x /= 8;
		pix->y /= 8;
		pix->pos_x /= 8;
		pix->pos_y /= 8;
	}
}


void  GetBidMVD()
{
	Macroblock*    currMB     =&img->mb_data[img->current_mb_nr];
	int            i,j,step_v0,step_h0 ,j0,i0,k,mv_mode,step_h,step_v,l,m,curr_mvd;
	int            delta_P,iTRp,DistanceIndexFw,DistanceIndexBw,delta_PB,pmv[2],i4,j4;				  
	int            current_tr,refframe=0,fw_refframe;


	if(currMB->mb_type!=I_MB)
	{				
		step_h0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][0] >> 3);
		step_v0         = (input->blc_size[IS_P8x8(currMB) ? 4 : currMB->mb_type][1] >> 3);
	}

	for (j0=0; j0<2; )
	{ 
		if((currMB->mb_type==I_MB&&j0==0)) { j0 += 1; continue;} //Intra 

		for (i0=0; i0<2; )
		{
			k=j0*2+i0;

			if(currMB->b8pdir[k] == 2 && currMB->b8mode[k] != 0)
			{
				int use_scaled_mv = 0;
				mv_mode = currMB->b8mode[k];
				step_h     = input->blc_size[mv_mode][0] >> 3;
				step_v     = input->blc_size[mv_mode][1] >> 3;


				current_tr  = 2*(/*img->tr*/picture_distance/2);
				///////////////////////backward vector////////////////////////////////////////
				refframe  = 0;
				fw_refframe = fw_refFrArr[img->block_y/2+j0][img->block_x/2+i0];
				for (j=j0; j<(j0+step_v0); j+=step_v)
					for (i=i0; i<(i0+step_h0); i+=step_h)
					{ 
						{
							SetMotionVectorPredictor (pmv,bw_refFrArr,tmp_bwMV,refframe,i*8, j*8, 8*step_h, 8*step_v, -1, 0);
						}
						for (k=0; k<2; k++) 
						{
							j4 = img->block_y/2+j;
							i4 = img->block_x/2+i;	
							delta_P = 2*(img->imgtr_next_P_frm - img->imgtr_last_P_frm);
							delta_P = (delta_P + 512)%512;
							iTRp = (refframe+1)*delta_P;  //the lates backward reference
							iTRp     = (iTRp + 512)%512;
							delta_PB = 2*(picture_distance - img->imgtr_last_P_frm);
							delta_PB = (delta_PB + 512)%512;

							DistanceIndexFw = delta_PB;
							DistanceIndexFw    = (DistanceIndexFw + 512)%512;
							DistanceIndexBw    = iTRp - DistanceIndexFw;      
							DistanceIndexBw    = (DistanceIndexBw + 512)%512;
							curr_mvd = - ((tmp_fwMV[k][j4][i4+4]*DistanceIndexBw*(512/DistanceIndexFw)+256)>>9);
							//--- store (oversampled) mvd ---
							for (l=0; l < step_v; l++) 
								for (m=0; m < step_h; m++)    
									currMB->mvd[1][j+l][i+m][k] = curr_mvd-pmv[k];
						}
					}
			}
			i0+=max(1,step_h0);
		}
		j0+=max(1,step_v0);
	}
}